Haskell 是否总是知道哪个“返回”?打电话?
我定义 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这里有几个大问题。
首先,
Monad
实例必须具有 kind* -> *。这意味着它们至少需要一个类型变量,而您的
Something
没有任何类型变量。进行比较:看看
Maybe
、IO
和Either String
在使用它们之前如何需要一个类型参数?对于Something
,没有地方可以填写类型参数。因此您需要将定义更改为:第二个大问题是中的
>>=
你的 Monad 实例是错误的。通常不能使用 do 表示法,因为它只会调用Monad
函数return
和>>=
。所以你必须在没有任何 monad 函数的情况下写出来,无论是 do 符号还是调用>>=
或return
。>>=
的定义比您预期的要简单。展开m
很容易,因为您只需要在Something
构造函数上进行模式匹配。还有f :: a -> m b
,因此您无需担心再次将其包装起来,因为f
会为您完成此操作。虽然一般无法解开一个 monad,但是很多特定的 monad 都可以解开。
请注意,在 monad 实例声明中使用 do 表示法或
>>=
并没有语法上的错误。问题在于>>=
是递归定义的,因此当您尝试使用它时,程序会进入无限循环。(注意这里定义的
Something
是 Identity 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 yourSomething
doesn't have any. For comparison:See how each of
Maybe
,IO
, andEither String
need a type parameter before you can use them? WithSomething
, there's no place for the type parameter to fill in. So you need to change your definition to:The second big problem is that the
>>=
in your Monad instance is wrong. You generally can't use do-notation because that just calls theMonad
functionsreturn
and>>=
. So you have to write it out without any monad functions, either do-notation or calling>>=
orreturn
.The definition of
>>=
is simpler than you expected. Unwrappingm
is easy because you just need to pattern-match on theSomething
constructor. Alsof :: a -> m b
, so you don't need to worry about wrapping it up again, becausef
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 beSomething b
the compiler will automatically use the Monad instance forSomething
. (I think you meant the last line to bedoMagicTo var
).主要问题是您对
>>=
的定义是循环的。Haskell 的 do 语法是
>>=
和>>
链的语法糖,所以你的定义Desugars 为
所以你定义
m >; >= f
为m >>= \...
,这是循环的。您需要使用
>>=
定义如何从 m 中提取值以传递给f
。此外,您的f
应该返回一个单子值,因此使用return
在这里是错误的(这更接近您定义fmap
的方式) 。>>=
对于Something
的定义可以是: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 definitionDesugars to
So you're defining
m >>= f
asm >>= \...
, which is circular.What you need to do with
>>=
is define how to extract a value from m to pass tof
. In addition, yourf
should return a monadic value, so usingreturn
is wrong here (this is closer to how you'd definefmap
).A definition of
>>=
forSomething
could be:This is the Identity Monad - there's a good deal written about it - it's a good starting point for understanding how monads work.
关闭。这里的
return
是多余的,您需要向Something
类型构造函数添加一个类型参数。 编辑:这段代码仍然是错误的。>>=
的定义是循环的。请参阅其他答案以获取更多信息。由于
>>=
的定义位于instance Monad Something where
下,> ;>=
的类型是Something a -> (a -> 某物 b) ->一些b。因此它可以判断
f var
必须是Something b
类型。这里谷歌搜索的术语是“类型推断”是的。同样,这是类型推断。如果编译器无法推断出您想要的类型,它会告诉您。但通常可以。
Close. The
return
is redundant here and you need to add a type parameter to yourSomething
type constructor. Edit: This code is still wrong. The definition of>>=
is circular. See the other answers for more information.Since your definition for
>>=
is under theinstance Monad Something where
,>>=
's type isSomething a -> (a -> Something b) -> Something b
. So it can tell thatf var
has to be of typeSomething b
. The term to google here is "type inference"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.