Это также можно сделать, используя Стрелки :
import Control.Arrow ((&&&), (>>>), Arrow(..))
split_combine :: Arrow cat => cat (b, c) d -> cat a b -> cat a c -> cat a d
split_combine h f g = (f &&& g) >>> h
letter_or_digit = split_combine (uncurry (||)) isLetter isDigit
&&&
(не относится к &&
), разделяет вход;>>>
- это стрелка / состав категории.
Вот пример:
> map letter_or_digit "aQ_%8"
[True,True,False,False,True]
Это работает, потому что функции - ->
- являются экземплярами Category и Arrow.Сравнение сигнатур типов с примерами Дона liftA2
и liftM2
показывает сходство:
> :t split_combine
split_combine :: Arrow cat => cat (b, c) d -> cat a b -> cat a c -> cat a d
> :t liftA2
liftA2 :: Applicative f => (b -> c -> d) -> f b -> f c -> f d
Кроме карри, обратите внимание, что вы можете почти преобразовать первый тип во второй, подставив cat a ---> f
и Arrow ---> Applicative
(другое отличие в том, что split_combine
не ограничивается принятием чистых функций в своем 1-м аргументе; хотя, вероятно, это и не важно).