我被困在这里,我可以制作data类型实例,Monad但我无法弄清楚我是如何做到的newtype.
newtype Val a = Val {getVal :: [a]} deriving (Show)
instance Monad Val where
return = Val
(>>=) (Val {getVal = l}) f = map f l
Run Code Online (Sandbox Code Playgroud)
如果我这样写:
instance Monad Val where
return = Val
(>>=) (Val {getVal = l}) f = {getVal = map f l}
Run Code Online (Sandbox Code Playgroud)
然后我得到错误,它说parse error on input {
.
我如何制作newtypeMonad的实例?
这里有几个问题.首先,您必须在大括号之前指定记录名称.所以你要
(>>=) (Val {getVal = l}) f = Val {getVal = map f l}
Run Code Online (Sandbox Code Playgroud)
现在,你的任何一个函数都不会立即进行类型检查.但修复并不太难,因为您只是委托已经存在的列表monad实例.你return很接近,但你需要将结果包装在一个列表中.
return x = Val [x]
Run Code Online (Sandbox Code Playgroud)
同样,你不想map在记录里面.你想要列表monad版本(>>=).
(>>=) (Val {getVal = l}) f = Val {getVal = l >>= f}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这仍然不会很严重,因为f它旨在返回Val而不是[].我们需要在monad操作中进行修正.
(>>=) (Val {getVal = l}) f = Val {getVal = l >>= getVal . f}
Run Code Online (Sandbox Code Playgroud)
在那之后,你可能会Applicative因为成为超类而感到错误Monad.这可以通过一些辅助函数的简单应用来解决.
import Control.Monad
-- ...
instance Functor Val where
fmap = liftM
instance Applicative Val where
pure = return
(<*>) = ap
Run Code Online (Sandbox Code Playgroud)
现在一切都应该编译.
作为旁注,如果你正在使用GHC,那么有一个方便的功能GeneralizedNewtypeDeriving可以自动为你提供newtype数据类型的实例.你可以像这样使用它
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Val a = Val {getVal :: [a]}
deriving (Show, Functor, Applicative, Monad)
Run Code Online (Sandbox Code Playgroud)
这只适用于newtype,而不是data,它只适用于GHC,因此如果您希望您的代码可以跨编译器移植,请不要使用它.