12

在阅读(并浏览了一些部分)Wadler 关于 monad 的论文之后,我决定更仔细地阅读这篇论文,为他描述的每个 monad 定义函子和应用实例。使用类型同义词

type M a = State -> (a, State)
type State = Int

Wadler 用于定义状态 monad,我有以下内容(使用相关名称,以便稍后使用 newtype 声明定义它们)。

fmap' :: (a -> b) -> M a -> M b
fmap' f m = \st -> let (a, s) = m st in (f a, s)

pure' :: a -> M a
pure' a = \st -> (a, st)

(<@>) :: M (a -> b) -> M a -> M b
sf <@> sv = \st -> let (f, st1) = sf st
                       (a, st2) = sv st1
                    in (f a, st2)

return' :: a -> M a
return' a = pure' a

bind :: M a -> (a -> M b) -> M b
m `bind` f = \st -> let (a, st1) = m st
                        (b, st2) = f a st1
                     in (b, st2)

当我切换到在 newtype 声明中使用类型构造函数时,例如,

newtype S a = S (State -> (a, State))

一切都崩溃了。一切都只是轻微的修改,例如,

instance Functor S where
 fmap f (S m) = S (\st -> let (a, s) = m st in (f a, s)) 

instance Applicative S where
 pure a = S (\st -> (a, st))

然而,由于 lambda 表达式隐藏在该类型构造函数中,因此在 GHC 中没有任何运行。现在我看到的唯一解决方案是定义一个函数:

isntThisAnnoying s (S m) = m s

为了将 s 绑定到 'st' 并实际返回一个值,例如,

fmap f m = S (\st -> let (a, s) = isntThisAnnoying st m in (f a, s))

还有另一种不使用这些辅助功能的方法吗?

4

2 回答 2

11

如果你看这里,你会看到他们是这样定义的:

newtype State s a = State { runState :: (s -> (a,s)) }

以便为内部 lambda 命名。

于 2010-08-20T18:45:25.453 回答
5

通常的方法是定义newtype newtype S a = S {runState : State -> (a, State)}. 然后isntThisAnnoying s (S m)你可以写runState t swhere tis the same as而不是你的S m
您必须使用 anewtype因为类型同义词不能是类型类实例。

于 2010-08-20T18:46:51.033 回答