给定类型为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
函数。或者是吗?
答案 0 :(得分:5)
Applicative
类有<*>
运算符(通常发音为&#34; ap&#34;,对于大多数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
,那么<*>
的重复 ap 折叠(得到它?)将更多参数传递给包装函数。
答案 1 :(得分: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
,这很好。