2010-08-20 60 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,因爲類型同義詞不能是類型類實例。