【问题标题】:Problem with 'rigid type variable' in a Monad in haskellHaskell中Monad中的“刚性类型变量”问题
【发布时间】:2020-07-14 12:40:52
【问题描述】:

我正在尝试更好地学习 monad,并在 Haskell 中使用它。我以这种方式定义了一个 monad:

module TESTMonad where

import Control.Monad

newtype TEST i = TEST {getTEST :: ((i, Int), Int)} deriving (Show, Eq, Ord)

instance Functor TEST where
    fmap f (TEST ((x,y), z)) = TEST ((f x, y), z)

instance Applicative TEST where
    pure = return
    tf <*> tx = tf >>= \f -> tx >>= \x -> return (f x)

instance Monad TEST where
    return x = TEST ((x, 1), 1)
    (TEST ((x, y), z)) >>= f = TEST ((plusOne a, b), c)
        where
                ((a, b), c) = getTEST (f x)

plusOne :: Int -> Int
plusOne x = x+1

但我在尝试编译时收到以下错误:

TESTMonad.hs:16:47: error:
    • Couldn't match expected type ‘Int’ with actual type ‘b’
      ‘b’ is a rigid type variable bound by
        the type signature for:
          (>>=) :: forall a b. TEST a -> (a -> TEST b) -> TEST b
        at TESTMonad.hs:16:24
    • In the first argument of ‘plusOne’, namely ‘a’
      In the expression: plusOne a
      In the expression: (plusOne a, b)
    • Relevant bindings include
        a :: b (bound at TESTMonad.hs:18:19)
        f :: a -> TEST b (bound at TESTMonad.hs:16:28)
        (>>=) :: TEST a -> (a -> TEST b) -> TEST b
          (bound at TESTMonad.hs:16:5)
Failed, modules loaded: none.

我清楚地知道我可能会以错误的方式做很多事情,但我不知道它们是什么。任何评论将不胜感激。提前谢谢!

【问题讨论】:

  • 是什么让您认为实现中的a 必须是Int? plusOne 只接受 Int 作为参数。
  • 换句话说,您的Monad 实例必须使用any 类型,但您的定义使用plusOne,这要求它是Int。即使将其放宽到 plusOne :: Num a =&gt; a -&gt; a 对您的 Monad 实例来说仍然过于严格。
  • @Robin Zigmond 是的,但是如果我希望它是“Int”呢?在这种情况下,我应该如何定义 monad TEST 并输入“TEST i”?
  • @chepner 是的,我之前尝试过,但没有成功。如果我希望 monad 只接受 "Int" 并使其类型更具体一点,我该怎么办?
  • 你不能;你描述的不是Monad。

标签: haskell monads


【解决方案1】:

Monad 实例不能被约束。 (&gt;&gt;=) 的类型必须是

Monad m => m a -> (a -> m b) -> m b

但是你的定义,使用plusOne :: Int -&gt; Int,使得类型

Monad m => m Int -> (Int -> m Int) -> m Int

您可以安全地将plusOne 应用到包裹在TEST 中的任何其他值,因为它们已经定义为Ints。

(&gt;&gt;=) 的定义不知道x 的类型可能是什么,调用者可以选择f,所以它也不知道f x 的类型可能是什么。因此,除了按原样使用它之外,您实际上无法对它做任何事情。

【讨论】:

  • 但是这种类型不起作用,因为 Applicative 中的 ``` `` 的类型是 `` () :: f (a -> b) -> f a -> f b ```!
  • 请注意Applicative laws 之一是pure id &lt;*&gt; v == v。这意味着您必须保留右手参数的“上下文”。换句话说,TEST ((f, _), _) &lt;*&gt; TEST ((x, y), z) == TEST ((f x), y, z)。与pure x = TEST ((x, 1, 1) 配对,我认为这构成了一个有效的Applicative 实例;我将把它作为一个练习来验证这个定义是否满足其他三个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-09
  • 2011-03-12
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
相关资源
最近更新 更多