У нас есть следующие типы для функций:
traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
posts :: Functor f => ([Post] -> f [Post]) -> User -> f User
Давайте выстроим типы для traverse
и posts
(в таком порядке), чтобы мы могли видеть, что происходит (для этого я опущу ограничения класса типов), и добавим подразумеваемые круглые скобки вокруг результатов функций (a -> b -> c
— это ярлык для a -> (b -> c)
)
(a -> f b ) -> (t a -> f (t b))
([Post] -> f [Post]) -> (User -> f User)
Из этого мы видим, что a ~ User
, b ~ User
(~
здесь означает «отождествляется с» или «равно»), поэтому давайте специализируем обход и снова запишем типы функций:
(User -> f User) -> (t User -> f (t User))
([Post] -> f [Post]) -> (User -> f User)
Из этого мы видим, что композиция будет иметь тип (снова опуская ограничения)
([Post] -> f [Post]) -> (t User -> f (t User))
Или без необязательных скобок
([Post] -> f [Post]) -> t User -> f (t User)
А что теперь с ограничениями? Ну, использование posts
дает нам ограничение Functor f
, а traverse
дает нам Applicative f
и Traversable t
, но поскольку Applicative
является подклассом Functor
(он определен как class Functor f => Applicative f where -- ...
), нам не нужно указывать ограничение Functor f
, оно уже есть. .
Итак, нам осталось:
traverse . posts :: (Applicative f, Traversable t) =>
([Post] -> f [Post]) -> t User -> f (t User)
person
Mor A.
schedule
16.06.2018