我是Haskell的新手。这可能是愚蠢的问题。
由于Applicative类型类具有apply函数,该函数在相同的上下文中使用这些函数和数据。为什么它不能与众不同,却更通用。
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
为什么我们不能写这样的东西
class Functor f => Applicative f where
(<*>) :: Functor g => g (a -> b) -> f a -> g (f b)
(<*>) gab fa = fmap (\g -> fmap g fa) gab
(<<*>>) :: Functor g => (g (f a) -> f a) -> g (a -> b) -> f a -> f b
(<<*>>) peelOuter gab fa = peelOuter $ gab <*> fa
(>>*<<) :: Functor g => (g (f a) -> g a) -> g (a -> b) -> f a -> g b
(>>*<<) cleanInner gab fa = cleanInner $ gab <*> fa
可以如下使用
-- Extract List from maybe
elfm :: Maybe [a] -> [a]
elfm Nothing = []
elfm (Just xs) = xs
-- Fuse List elements in Maybe []
flem :: Monoid a => Maybe [a] -> Maybe a
flem Nothing = mempty
flem (Just xs) = Just $ foldl (<>) mempty xs
Just (*2) <*> [1,2,3,4]
-- Just [2,4,6,8]
(<<*>>) elfm (Just (*2)) [1,2,3,4]
-- [2,4,6,8]
(>>*<<) flem (Just (++ "Haskell")) ["Hello, "]
-- Just "Hello, Haskell"
而且我读到,拥有Applicatives的全部要点是Functor提升多参数函数的缺点。这样对吗?
而且我认为功能应用程序不符合预期。
add :: Num a => a -> a -> a
add a b = a + b
-- I want to apply [1,2,3] as First arguments and [4,5,6] as 2nd arguments.
-- Like add 1 4, add 2 4, add 3 6
-- But it is give all possibilities of combinations like a tree
-- <*>
-- (+1) (+2) (+3)
-- (1+4)(1+5)(1+6) (2+4)(2+5)(2+6) (3+4)(3+5)(3+6)
并且还将它们与批处理进行比较,但是没有给出非常真实的示例。请为此提供示例。
Applicative
的每个实例必须具有其自己的<*>
实现。这就是为什么我们首先要有类型类的原因。您的代码具有类本身定义的所有方法,实例一无所有。这意味着根本没有类型类。只有一堆通用函数。所有的肉都委派给peelOuter
和cleanInner
的参数。让我们更仔细地研究它们。它们或多或少是对称的,所以peelOuter
应该足够。
(<<*>>) :: Functor g => (g (f a) -> f a) -> g (a -> b) -> f a -> f b
(<<*>>) peelOuter gab fa = peelOuter $ gab <*> fa
实际上是gab
应该是类型类的方法,但是存在多个问题。
第一个涉及两个函子的问题,并且对于每个pair个函子需要分别实现gab
。也就是说,这里将有一个双参数类型类ApplicativePair
,并且每对都需要一个单独的实例。
第二个问题是不能为每对真正的gab
仿函数实现Applicative
。无法从Id a
提取Maybe (ID a)
,或从[a]
提取IO [a]
,或...
更糟糕的是,当f
和g
是同一个函子时,尚不清楚它是否始终可以实现。显然,当f
是单声道时,则仅是join
。但是,并非所有的求助词都是单子,而join
恰恰是一个求助词所缺少的单子。因此,即使gab
类型是可实现的,它也会违反某些monad法则。那是一件坏事?如果仍遵循适用法律,则不一定。但是,您没有提供任何法律,只有一堆功能。