Прочитав (и прочитав некоторые разделы) статью Вадлера о монадах, я решил более внимательно изучить статью, определив функтор и аппликативные примеры для каждой из описанных им монад. Использование типа синоним
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))
Есть ли другой способ сделать это, не используя эти вспомогательные функции?