身份Monad - Haskell中的行为差异?

时间:2018-05-20 22:11:46

标签: haskell monads identity

我最近在Haskell玩过Monads(仍然是一个相对初学者的所有这些)。我使用Identity Monad发现了一些有趣的行为(或者至少对我有趣)。

如果我写下以下功能:

let f = \x -> Identity 2 >>= \y -> x * y

然后执行:t我得到f :: Num b => Identity b -> Identity b。推断x是Identity (Num b)。我可以使用6调用该函数,然后得到结果12

但是,如果我像Maybe那样尝试相同的事情:

let g = \x -> Just 2 >>= \y -> x * y

<interactive>:2096:5: error:
    • Non type-variable argument in the constraint: Num (Maybe b)
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        g :: forall b. Num (Maybe b) => Maybe b -> Maybe b

因此,我需要明确返回Maybe或使用return。所以我这样做:let g = \x -> Just 2 >>= \y -> return $ x * y

一切正常。然而,我想知道Identity monad发生了什么。

首先,我尝试添加显式返回类型,如下所示:

let f = \x -> Identity 2 >>= \y -> Identity $ x * y

然后再次:t,我得到了f :: Num b => b -> Identity b。这是我第一次期待的。

如果推断x + yIdentity $包含在x之内,那么我会怀疑它如何能够处理y Identity Identity 5。所以我尝试了以下内容:

Identity 6 + 11,结果为Identity 5

6 + 11,结果再次为Maybe

然而,我会像Just 5一样尝试相同的

Just 6 + Just 5

6 + <interactive>:2116:1: error: • Non type-variable argument in the constraint: Num (Maybe a) (Use FlexibleContexts to permit this) • When checking the inferred type it :: forall a. (Num (Maybe a), Num a) => Maybe a

我收到以下错误:

FlexibleContexts

我尝试了<interactive>:2134:1: error: • No instance for (Num (Maybe a0)) arising from a use of ‘it’ • In the first argument of ‘print’, namely ‘it’ In a stmt of an interactive GHCi command: print it ,但我收到了以下错误:

Identity

我想知道是否有人可以解释为什么Maybe monad行为与FlexibleContexts不同?

还可以使用Maybe来获得与protected $token; public function __construct($token){ $this->token = $token; $this->checkToken(); } protected function checkToken() { if (current_method() == "POST" || "PUT" || "PATCH") { if (CSRF::verifyToken(@$_POST['token'])) { $this->checkPrefix(); } } elseif (current_method() == "GET" || "DELETE") { if (CSRF::verifyToken($this->token)) { $this->checkPrefix(); } } } monad相同的行为吗?我还没有能够让它继续工作。

非常感谢先进。

1 个答案:

答案 0 :(得分:3)

这是因为IdentityNum个实例而Maybe没有(你可以在GHCi中使用:i或查看{{3}来查看类型的实例}})。

因此,当您有\x -> Identity 2 >>= \y -> x * y时,*实际上是来自* Num的{​​{1}}个实例的Identity a(其中aNum它本身就是Int个实例,例如Double5 :: Num a => a等。

此外,Haskell中的数字文字是多态的:Num,因此它们可以像任何Int实例一样运行,而不是局限于特定的实例(如Double或{{1} })。当你尝试像Identity 5 + 6这样的事情时,就会发生这种情况。从6开始,Num a => Identity a被推断为类型为(+) :: Num a => a -> a -> a

您可以更明确地看到这一点:

ghci> :t 5
5 :: Num p => p
ghci> 5 :: Identity Int
Identity 5
ghci> 5 :: Maybe Int

<interactive>:12:1: error:
    • No instance for (Num (Maybe Int)) arising from the literal ‘5’
    • In the expression: 5 :: Maybe Int
      In an equation for ‘it’: it = 5 :: Maybe Int