3

Значение f с типом :: Applicative f => f (a -> b -> c). Каков наилучший способ сопоставления аргументов внутренней функции.Простой способ применения нескольких аргументов в Haskell

До сих пор я нашел следующее:

(\x -> x a b) <$> f

(flip ($ a) b) <$> f

($ b) <$> ($ a) <$> f

Я думаю, мой вопрос почему Haskell не имеет :: a -> b -> (a -> b -> c) -> c функцию. Или это?

ответ

5

Applicative класса имеет <*> оператор (обычно выраженный «ар», и эквивалентно Control.Monad.ap для большинства Monad с), что в сочетании с оператором <$> (сам только инфиксный псевдонимом для fmap) позволяет писать код как

-- f :: a -> b -> c 
-- fa :: Applicative f => f a 
-- fb :: Applicative f => f b 
f <$> fa <*> fb :: Applicative f => f c 

Если вам необходимо применить чистые аргументы, а затем использовать pure метод Applicative класса:

-- f :: a -> b -> c 
-- a :: a 
-- b :: b 
f <$> pure a <*> pure b :: Applicative f => f c 

Примером может быть

sumOfSquares :: Num a => a -> a -> a 
sumOfSquares a b = a * a + b * b 

> sumOfSquares <$> Just 1 <*> Just 2 
Just 5 
> sumOfSquares <$> Just 1 <*> Nothing 
Nothing 
> sumOfSquares <$> pure 1 <*> pure 2 :: Maybe Int 
5 
> sumOfSquares <$> readLn <*> readLn :: IO Int 
1<ENTER> 
2<ENTER> 
5 

Applicative f => f (a -> b -> c) строится по f <$> здесь, так что если вы уже что-то вроде

> let g :: IO (Int -> Int -> Int); g = undefined 

Тогда вы могли бы просто использовать его как

> g <*> pure 1 <*> pure 2 

Оператор <*> имеет тип

(<*>) :: Applicative f => f (a -> b) -> f a -> f b 

так что если ваша функция имеет тип x -> y -> z, то a ~ x и b ~ y -> z, поэтому повторил АП пликации <*> (получить его?) Проходит больше аргументов в вашей завернутые функции.

+0

Кажется, что использование 'Applicative' является более аккуратным и требует меньше скобок. Мне нравится '> $ <', предложенный @rampion, но это кажется более идиоматичным. – mgoszcz2

+1

@ mgoszcz2 Это определенно было бы более идиоматичным, поскольку в стандартной библиотеке он использует только определенные функции. В большинстве случаев, когда вы сталкиваетесь с этой проблемой, вы уже будете работать с аппликативным, а не просто функтором (не так много полезных функций, которые также не являются аппликативными), поэтому вам не нужно беспокоиться о добавлено слишком много ограничений. Решение rampion хорошо, но строка 'f> $ < a > $ 'и' <*> '. Вероятно, я бы выбрал более легкий для ввода оператор для этого в производственном коде, если я собираюсь использовать его много. – bheklilr

+0

bheklilr: согласовано во всех точках. Я думал об использовании '<¢>' вместо этого, но это немного жестоко на пальцах моей клавиатуры :) – rampion

2

Мы получили

(<$>) :: Functor f => (a -> b) -> f a -> f b 

Но вы хотите противоположный

(>$<) :: Functor f => f (a -> b) -> a -> f b 

Что мы можем легко определить:

(>$<) f a = ($a) <$> f 

Так дал

f :: Functor f => f (a -> b -> c) 
a :: a 
b :: b 

Тогда

f >$< a :: f (b -> c) 
f >$<a>$< b :: f c 

Это не так, как идиоматическое <*>, но это работает для всех Functor с, а не только Applicative с, что приятно.

Смежные вопросы