Haskell 是否总是知道哪个“返回”?打电话?

发布于 2024-12-11 11:20:37 字数 793 浏览 1 评论 0原文

我定义 monad 的实例如下:

data Something = Something a

instance Monad Something where
    return a = Something a        --Wraps a in 'Something', correct?
    m >>= f = do
        var <- m
        return $ f var            --I want this to pass var to f, then wrap the result
                                  --back up in the 'Something' monad with the return I
                                  --Just defined

问题是 ->

1:我所做的事情是否存在任何明显的错误/误解?

2:Haskell 是否知道从 m >>= f 调用我上面定义的 return

3:如果我出于某种原因定义了另一个函数,

f :: Something a -> Something b
f x = do
    var <- x
    return $ doMagicTo x

return 会调用 return我在 monad 实例中定义并将 x 包装在 Something 中?

I am defining an instance of a monad as follows:

data Something = Something a

instance Monad Something where
    return a = Something a        --Wraps a in 'Something', correct?
    m >>= f = do
        var <- m
        return $ f var            --I want this to pass var to f, then wrap the result
                                  --back up in the 'Something' monad with the return I
                                  --Just defined

The questions are ->

1: Are there any glaring errors/misconceptions with what I am doing?

2: Will Haskell know to call the return I have defined above from m >>= f

3: If I for some reason define another function

f :: Something a -> Something b
f x = do
    var <- x
    return $ doMagicTo x

Will return call the return I defined in the monad instance and wrap x in Something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

北城孤痞 2024-12-18 11:20:37

这里有几个大问题。

首先,Monad 实例必须具有 kind * -> *。这意味着它们至少需要一个类型变量,而您的Something 没有任何类型变量。进行比较:

-- kind * -> *
Maybe
IO
Either String

-- kind *
Maybe Int
IO ()
Either String Double

看看 MaybeIOEither String 在使用它们之前如何需要一个类型参数?对于 Something,没有地方可以填写类型参数。因此您需要将定义更改为:

data Something a = Something a

第二个大问题是中的 >>=你的 Monad 实例是错误的。通常不能使用 do 表示法,因为它只会调用 Monad 函数 return>>=。所以你必须在没有任何 monad 函数的情况下写出来,无论是 do 符号还是调用 >>=return

instance Monad Something where
    return a = Something a        --Wraps a in 'Something'
    (Something m) >>= f = f m     --unwraps m and applies it to f

>>= 的定义比您预期的要简单。展开 m 很容易,因为您只需要在 Something 构造函数上进行模式匹配。还有f :: a -> m b,因此您无需担心再次将其包装起来,因为 f 会为您完成此操作。

虽然一般无法解开一个 monad,但是很多特定的 monad 都可以解开。

请注意,在 monad 实例声明中使用 do 表示法或 >>= 并没有语法上的错误。问题在于 >>= 是递归定义的,因此当您尝试使用它时,程序会进入无限循环。

(注意这里定义的 SomethingIdentity monad

对于第三个问题,是的,Monad 实例中定义的 return 函数将被调用。类型类按类型分派,并且正如您指定的类型必须是 Something b ,编译器将自动使用 Something 的 Monad 实例。 (我认为你的意思是最后一行是doMagicTo var)。

There are a few big problems here.

First, a Monad instance must have kind * -> *. That means they need at least one type variable, where your Something doesn't have any. For comparison:

-- kind * -> *
Maybe
IO
Either String

-- kind *
Maybe Int
IO ()
Either String Double

See how each of Maybe, IO, and Either String need a type parameter before you can use them? With Something, there's no place for the type parameter to fill in. So you need to change your definition to:

data Something a = Something a

The second big problem is that the >>= in your Monad instance is wrong. You generally can't use do-notation because that just calls the Monad functions return and >>=. So you have to write it out without any monad functions, either do-notation or calling >>= or return.

instance Monad Something where
    return a = Something a        --Wraps a in 'Something'
    (Something m) >>= f = f m     --unwraps m and applies it to f

The definition of >>= is simpler than you expected. Unwrapping m is easy because you just need to pattern-match on the Something constructor. Also f :: a -> m b, so you don't need to worry about wrapping it up again, because f does that for you.

While there's no way to unwrap a monad in general, very many specific monads can be unwrapped.

Be aware that there's nothing syntactically wrong with using do-notation or >>= in the monad instance declaration. The problem is that >>= is defined recursively so the program goes into an endless loop when you try to use it.

(N.B. Something as defined here is the Identity monad)

For your third question, yes the return function defined in the Monad instance is the one that will be called. Type classes are dispatched by type, and as you've specified the type must be Something b the compiler will automatically use the Monad instance for Something. (I think you meant the last line to be doMagicTo var).

忘年祭陌 2024-12-18 11:20:37

主要问题是您对 >>= 的定义是循环的。

Haskell 的 do 语法是 >>=>> 链的语法糖,所以你的定义

m >>= f = do
    var <- m
    return $ f var         

Desugars 为

m >>= f = 
    m >>= \var -> 
    return $ f var

所以你定义 m >; >= fm >>= \...,这是循环的。

您需要使用 >>= 定义如何从 m 中提取值以传递给 f。此外,您的 f 应该返回一个单子值,因此使用 return 在这里是错误的(这更接近您定义 fmap 的方式) 。

>>= 对于 Something 的定义可以是:

(Something a) >>= f = f a

This is the Identity Monad - 有很多关于它的文章 - 这是理解 monad 的一个很好的起点工作。

The main issue is that your definition of >>= is circular.

Haskell's do syntax is syntatic sugar for chains of >>= and >>, so your definition

m >>= f = do
    var <- m
    return $ f var         

Desugars to

m >>= f = 
    m >>= \var -> 
    return $ f var

So you're defining m >>= f as m >>= \..., which is circular.

What you need to do with >>= is define how to extract a value from m to pass to f. In addition, your f should return a monadic value, so using return is wrong here (this is closer to how you'd define fmap).

A definition of >>= for Something could be:

(Something a) >>= f = f a

This is the Identity Monad - there's a good deal written about it - it's a good starting point for understanding how monads work.

无远思近则忧 2024-12-18 11:20:37
  1. 关闭。这里的 return 是多余的,您需要向 Something 类型构造函数添加一个类型参数。 编辑:这段代码仍然是错误的。 >>= 的定义是循环的。请参阅其他答案以获取更多信息。

    data Something a = Something a
    
    实例 Monad 某事在哪里
        返回 a = 某个东西 a
        m>>=f=do
            var<-m
            变量
    
  2. 由于 >>= 的定义位于 instance Monad Something where 下,> ;>= 的类型是 Something a -> (a -> 某物 b) ->一些b。因此它可以判断 f var 必须是 Something b 类型。这里谷歌搜索的术语是“类型推断”

  3. 是的。同样,这是类型推断。如果编译器无法推断出您想要的类型,它会告诉您。但通常可以。

  1. Close. The return is redundant here and you need to add a type parameter to your Something type constructor. Edit: This code is still wrong. The definition of >>= is circular. See the other answers for more information.

    data Something a = Something a
    
    instance Monad Something where
        return a = Something a
        m >>= f = do
            var <- m
            f var
    
  2. Since your definition for >>= is under the instance Monad Something where, >>='s type is Something a -> (a -> Something b) -> Something b. So it can tell that f var has to be of type Something b. The term to google here is "type inference"

  3. Yes. Again, this is type inference. If the compiler can't infer the type you want, it will tell you so. But usually it can.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文