在 Haskell 中应用多个参数的更简单方法

Easier way to apply multiple arguments in Haskell

给定值 f,类型为 :: Applicative f => f (a -> b -> c),将参数映射到内部函数的最佳方法是什么。

到目前为止,我发现了以下内容:

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

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

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

我想我的问题是为什么 Haskell 没有 :: a -> b -> (a -> b -> c) -> c 函数。或者是吗?

Applicative class 具有 <*> 运算符(通常发音为 "ap",对于大多数 Monad 来说等同于 Control.Monad.ap ),它与 ​​<$> 运算符(本身只是 fmap 的中缀别名)相结合,让您可以编写类似

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

如果您需要应用纯参数,则使用 Applicative class:

pure 方法
-- 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 ~ xb ~ y -> z,所以重复ap<*>的应用(明白了吗?)将更多参数传递给包装函数。

我们有

(<$>) :: 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,这很好。