我想我找到了“不存在的单子”

Nam*_*die 4 monads haskell default ghci

我发现了Haskell的怪异特征,这使我相信我在错误地思考。我认为在Haskell中,应该有一些“不存在”的 monad。这是由于以下原因。

Prelude> return 1
1
Prelude> return 1 >>= \x -> if even x then return True else return False
False
Run Code Online (Sandbox Code Playgroud)

>>=是类型的m a -> (a -> m b) -> m b,其中m可以是任何单子。我的理论是这样的:由于return 1评估仅是1return 1可以认为是1提升为包裹在“不存在”单子内部的值。Haskell抓住了这一事实并评估了整个表达式

return 1 >>= \x -> if even x then return True else return False
Run Code Online (Sandbox Code Playgroud)

False,因为它必须产生一个“不存在False,其仅是一个False

但是,我以前从未听说过这种“不存在”的单子。

我确信我用错误的方式对其进行了理论化,因为如果“不存在1是公正的1,则以下表达式必须是类型一致的,但事实并非如此。它是以上版本的修改版本。

1 >>= \x -> if even x then return True else return False

<interactive>:57:1: error:
    • Could not deduce (Integral a0)
      from the context: (Monad m, Integral a, Num (m a))
        bound by the inferred type for ‘it’:
                   forall (m :: * -> *) a. (Monad m, Integral a, Num (m a)) => m Bool
        at <interactive>:57:1-56
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for the inferred type for ‘it’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the inferred type
        it :: forall (m :: * -> *) a.
              (Monad m, Integral a, Num (m a)) =>
              m Bool
Run Code Online (Sandbox Code Playgroud)

因此,我的理论必须存在矛盾。我想念什么?

Jos*_*ica 14

return 1不只是1。您认为的是“不存在的单子”确实是IO。使用时return 1,GHCi假设您的意思是IO,然后有帮助地执行IO表达式并显示结果。您收到一个类型错误,1 >>= ...因为1不是monad。

正如@bradrn 在评论中提到的那样,通常GHCi自动运行IO a您提供的任何值,然后打印出返回的值。如果为GHCi提供非IO类型值,它将仅打印该值(如果可以)。

顺便说一句,有一个monad被称为Identity,它实际上就像您所说的那样是“不存在的monad”,因为无论您输入什么,它return x都是同构的x。但是,它不会自动使用。您需要手动包装和拆开包装才能使用它。

  • 我认为您的答案解释了我观察到的另一种行为:GHCI对于`return(Just 1)`和`Just 1 &gt;&gt; = return`显示相同的结果。前一个表达式本身的计算结果为“ IO(Just 1)”,并且由于包装了“ IO” monad而显示为“ Just 1”。在后一种情况下,表达式的计算结果为“仅1”,而GHCI只是将值打印出来。 (8认同)
  • 没错,@ Namudon'tdie。通常,GHCi自动运行您提供的任何“ IO a”值,然后打印出它返回的值。如果给它一个非`IO`类型,它将只打印结果(如果可以)。 (3认同)