【发布时间】: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 => a -> a对您的Monad实例来说仍然过于严格。 -
@Robin Zigmond 是的,但是如果我希望它是“Int”呢?在这种情况下,我应该如何定义 monad TEST 并输入“TEST i”?
-
@chepner 是的,我之前尝试过,但没有成功。如果我希望 monad 只接受 "Int" 并使其类型更具体一点,我该怎么办?
-
你不能;你描述的不是
Monad。