Функция составная подсказка
Просто ищу объяснение, как работает следующая композиция:
(=<<) . return
где
(=<<) :: (a -> m b) -> m a -> m b
return :: a -> m a
(.) :: (b -> c) -> (a -> b) -> a -> c
Окончательный тип:
GHCi> :t (=<<) . return
(=<<) . return :: Monad m => m b -> m a -> m b
Я не могу понять, как можно сопоставить ма с (а -> мб), т.е. как применить результат return, который является простым типом, к первому аргументу (=<<), ожидающему тип функции?
2 ответа
Объяснение:
- Ваш
return
(возможно, неожиданно) другой монады, чем ваша=<<
, - Монада, которую он использует, является монадой читателя
(->) r
,
Компилятор пытается унифицировать результат return :: c -> m' c
с первым аргументом (a -> m b) -> m a -> m b
так что унифицировать m' c
с a -> m b
, Единственная возможность состоит в том, что m'
читатель монада (->) r
для некоторых r
, Далее он пытается объединить (->) r c
с (преобразуется в префиксную нотацию) (->) a (m b)
, который решается установкой r
в a
а также c
в m b
, Таким образом, после объединения, компилятор получает наиболее общий тип
return :: (m b) -> ((->) a (m b))
или в обычной записи инфикса
return :: (m b) -> (a -> m b)
Смотрите также:
- Как использовать (->) экземпляры Monad и путаница с (->)
- Источник, где экземпляр
Monad ((->) r)
определено.
Редактировать: чтобы определить монаду, нам нужен (частично примененный) тип вида * -> *
, Это почти всегда частично применяемые конструкторы данных, но в данном конкретном случае мы рассматриваем ->
как оператор типа, который принимает 2 аргумента типа и создает новый тип (тип функции). Так для любого данного типа r
частично примененное выражение (->) r
это тип вида * -> *
, Как оказалось, существует простой способ описать операции монады над ним. См. Монаду Control.Reader, а также эту статью, которая объясняет это. Операции с монадой для Reader
реализованы точно так же, как для (->)
Единственное отличие состоит в том, что Reader
оборачивает операции в отдельный тип данных.
Я снова, с писанинами, кладу вещи рядом, чтобы помочь в визуальном понимании:
g = ((=<<) . return) {-
((=<<) . return) x y
=== (=<<) (return x) y return :: a' -> m' a'
(=<<) :: (a -> m b) -> m a -> m b return x :: m' a' , x :: a'
m' a' m' ~ ((->) a) , a' ~ m b
return x === const x -- instance Monad ((->) a) where return = const
g x y === y >>= (\_ -> x) === y >> x (!!)
-}
g :: m b -> m a -> m b
Так что, как оказалось (и это было очевидно из сигнатуры типа), g === flip (>>)
:
Prelude> ((=<<).return) [1] "xyz" -- === (=<<) (const [1]) "xyz"
-- === "xyz" >>= const [1]
-- === "xyz" >> [1]
-- === (>> [1]) "xyz"
[1,1,1]