2010-08-20 40 views
12

在阅读Wadler关于monad的论文(并略读了部分内容)之后,我决定更仔细地研读论文,为他描述的每个monad定义函子和应用实例。使用类型同义词函数/ Haskell中状态的应用实例

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

Wadler用来定义状态单子,我有以下的(使用相关的名字,所以我可以用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)) 

但是没有在GHC由于事实lambda表达式是隐藏该类型的构造函数中运行。现在我看到的唯一的解决办法是定义一个函数:

isntThisAnnoying s (S m) = m s 

为了送绑定到“ST”,实际上返回一个值,例如,

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

是否有另一种方式做到这一点那不使用这些辅助功能?

回答

11

如果你看看here,你会发现它们定义是这样:

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

以便给内部拉姆达的名称。

+2

这也意味着'runState = flip isntThisAnnoying'。 – kennytm 2010-08-20 18:48:26

+1

好的 - 所以虽然还需要一个辅助功能,但我可以使用记录来定义类型,免费获取该功能。那么你所说的是,没有办法避免使用像'runState'或'run'这样的函数。谢谢。 – danportin 2010-08-20 21:40:33

+0

如果它伤害你想它作为一个函数,而不是想它作为一个结构字段访问器。 :-) – 2010-08-21 00:50:37

4

通常的方法是定义newtype newtype S a = S {runState : State -> (a, State)}。然后,您可以编写runState t s而不是您的isntThisAnnoying s (S m),其中tS m相同。
您必须使用newtype,因为类型同义词不能是类型类实例。