Функтор / Аппликативные экземпляры для State в Haskell - PullRequest
11 голосов
/ 20 августа 2010

Прочитав (и прочитав некоторые разделы) статью Вадлера о монадах, я решил более внимательно изучить статью, определив функтор и аппликативные примеры для каждой из описанных им монад. Использование типа синоним

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 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 ничего не работает из-за того, что лямбда-выражение скрыто внутри этого конструктора типов. Теперь единственное решение, которое я вижу, это определить функцию:

isntThisAnnoying s (S m) = m s

для привязки s к 'st' и фактического возврата значения, например,

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

Есть ли другой способ сделать это, не используя эти вспомогательные функции?

Ответы [ 2 ]

11 голосов
/ 20 августа 2010

Если вы посмотрите здесь , вы увидите, что они определяют его следующим образом:

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

, чтобы дать внутренней лямбде имя.

4 голосов
/ 20 августа 2010

Обычный способ - определить newtype newtype S a = S {runState : State -> (a, State)}. Тогда вместо вашего isntThisAnnoying s (S m) вы можете написать runState t s, где t совпадает с S m.
Вы должны использовать newtype, поскольку синонимы типов не могут быть экземплярами классов типов.

...