Применить список булевых функций к двум аргументам в Haskell

У меня есть список функций типа a -> b -> Bool, и я пытаюсь применить их к двум входам и объединить результаты с All или же Any, У меня это работает с функциями одной переменной:

mconcat (map (All . ) [(<7),(>7),(==7)]) $ 6

но я не могу понять, как сделать то же самое с двумя переменными функциями.

Это работает:

mconcat (map (All . ) (map (uncurry) [(<),(>),(==)])) $ (,) 6 7

но это выглядит как уродливый обходной путь.

Есть лучший способ сделать это?

2 ответа

Решение

Это тот код, который пишет сам - нужно просто объединить типы. Но есть пара стандартных инструментов (а именно Applicative а также Traversable), который вы можете использовать, чтобы сделать ваш код короче.

в Data.Traversable модуль жизни sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a), Когда специализируется на [] экземпляр Traversable и функция аппликативная (->) r мы получаем:

sequenceA :: [r -> a] -> r -> [a]

Так sequenceA рывки -> снаружи [], применяя каждую функцию в списке к фиксированному аргументу.

sequenceA [(< 7), (> 7), (== 7)] :: (Num n, Ord n) => n -> [Bool]
-- equivalent to:
\n -> map ($ n) [(< 7), (> 7), (== 7)]

Итак, ваша первая функция может быть записана как

f :: (Num n, Ord n) => n -> Bool
f = and . sequenceA [(< 7), (> 7), (== 7)]

я использую and вместо mconcat . map (All .),

Для вашей второй функции, uncurry это правильный инструмент. Мы должны на карту uncurry через список бинарных функций, чтобы получить список унарных функций кортежей, чтобы мы могли поднять один аргумент, используя sequenceA, Так как traverse f = sequenceA . map f мы можем написать это как:

g :: Ord n => n -> n -> Bool
g = curry $ and . traverse uncurry [(<), (>), (==)]

(NB, для любого правильно реализованного экземпляра Ord, > а также < должен быть взаимоисключающим. Так что обе эти функции всегда будут возвращать False.)

Близкая альтернатива оригинальному коду:

mconcat (map (\f a b -> All (f a b)) [(<),(<=)]) 3 4

Можно еще переписать \f a b -> All (f a b) в бессмысленном стиле:

mconcat (map ((.) (All .)) [(<),(<=)]) 3 4
Другие вопросы по тегам