简体   繁体   English

在 Haskell 为什么应用程序需要在同一上下文中获取态射和数据?

[英]In Haskell why Applicatives need to take morphisms and data in same Context?

I am new to Haskell.我是 Haskell 的新手。 This may be stupid question.这可能是个愚蠢的问题。

As the Applicative typeclass has apply function that takes the functions and data in the same context.由于 Applicative 类型类应用了 function,它在相同的上下文中获取函数和数据。 Why can't it be different and be more generic.为什么它不能不同并且更通用。

class Functor f => Applicative f where
    pure :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

Why can't we write something like this为什么我们不能写这样的东西

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

It can be used as below它可以如下使用

-- 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"

And I read that the whole point of having Applicatives is the drawback of Functors lifting multi argument functions.而且我读到拥有 Applicatives 的全部意义在于 Functors 提升多参数函数的缺点。 Is this right?这是正确的吗?

And I don't think the function application is as expected.而且我不认为 function 应用程序符合预期。

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)

And also they are compared to batch processing, but no quite real life example is given.并且它们也与批处理进行了比较,但没有给出非常真实的例子。 Please provide an example for this.请为此提供一个示例。

Each instance of Applicative necessarily has its own implementation of <*> . Applicative的每个实例都必须有自己的<*>实现。 That's why we have type classes in the first place.这就是为什么我们首先要有类型类。 Your code has all the methods defined in the class itself, nothing is left for instances.您的代码具有 class 本身定义的所有方法,没有任何实例。 This means there isn't much of a type class at all.这意味着根本没有 class 类型。 There's just a bunch of generic functions.只有一堆通用函数。 All the meat is delegated to the arguments peelOuter and cleanInner of ('<<*>>) and (>>*<<) .所有的肉都被委托给('<<*>>)(>>*<<)peelOuter剥离外层和cleanInner Let's look at them more closely.让我们更仔细地看看它们。 They are more or less symmetrical so (<<*>>) should be enough.它们或多或少是对称的,所以(<<*>>)就足够了。

(<<*>>) :: Functor g => (g (f a) -> f a) -> g (a -> b) -> f a -> f b
(<<*>>) peelOuter gab fa = peelOuter $ gab <*> fa

It's actually peelOuter that should have been a method of a type class, but there is more than one problem with that.实际上, peelOuter应该是 class 类型的方法,但问题不止一个。

The first problem that there are two functors involved, and peelOuter needs to be implemented separately for each pair of functors.第一个问题是涉及到两个函子,并且需要为每一函子分别实现peelOuter That is, we would have a bi-parametric type class ApplicativePair here, and we would need a separate instance for each pair.也就是说,我们将在这里有一个双参数类型 class ApplicativePair ,我们需要为每一对单独的实例。

The second problem is that peelOuter cannot be implemented for every pair of bona fide Applicative functors.第二个问题是不能为每一对真正的Applicative函子实现peelOuter One cannot extract an Id a from a Maybe (Id a) , or a [a] from an IO [a] , or...不能从Maybe (Id a)中提取Id a a ,或者从IO [a] [a]或者...

Worse yet, it isn't clear if it is always implementable when f and g are the same functor.更糟糕的是,当fg是同一个函子时,它是否总是可以实现尚不清楚。 Clearly, when f is a monad, then it's just a join .显然,当f是一个单子时,它只是一个join Not all applicatives are monads however, and join is precisely what an applicative lacks to be a monad.然而,并非所有的应用程序都是单子,而join正是应用程序所缺乏的单子。 So peelOuter , even if such a type is implementable, would violate some monad laws.因此,即使这样的类型是可实现的, peelOuter也会违反一些单子定律。 Is that a bad thing?那是一件坏事? Not necessarily, if it still follows applicative laws.不一定,如果它仍然遵循适用法律。 You however have not supplied any laws, only a bunch of functions.但是,您没有提供任何法律,只有一堆功能。

Any two functors are Functor and Applicative functors.任何两个函子都是函子应用函子。 This coded with newtype Compose , see Data.Functor.Compose .这使用newtype Compose编码,请参阅Data.Functor.Compose

So, your examples can be solved by newtype Compose .因此,您的示例可以通过newtype Compose来解决。

-- Just (*2) <*> [1,2,3,4]
getCompose $ pure (*2) <*> Compose (Just [1,2,3,4])
-- or
getCompose $ (*2) <$> Compose (Just [1,2,3,4])
-- Just [2,4,6,8]

-- (<<*>>) elfm (Just (*2)) [1,2,3,4]
elfm . getCompose $ pure (*2) <*> Compose (Just [1,2,3,4])
-- or with toList (method of Foldable)
toList $ pure (*2) <*> Compose (Just [1,2,3,4])
-- or
toList $ (*2) <$> Compose (Just [1,2,3,4])
-- [2,4,6,8]

-- (>>*<<) flem (Just (++ "Haskell")) ["Hello, "]
flem . getCompose $ pure (++ "Haskell") <*> Compose (Just ["Hello, "])
-- or with toList and listToMaybe
listToMaybe . toList $ pure (++ "Haskell") <*> Compose (Just ["Hello, "])
-- or
listToMaybe . toList $ (++ "Haskell") <$> Compose (Just ["Hello, "])
-- or with head :: Foldable f => f a -> Maybe a
head $ (++ "Haskell") <$> Compose (Just ["Hello, "])
-- Just "Hello, Haskell"

About the last question.关于最后一个问题。 You have got an answer in comments by @Robin Zigmond.您在@Robin Zigmond 的评论中得到了答案。 It wrote about the newtype ZipList .它写了关于新newtype ZipList的文章。 With ZipList you can do:使用ZipList ,您可以:

getZipList $ (+) <$> ZipList [1,2,3] <*> ZipList [4,5,6]
-- [5,7,9]

So, one of the purposes of newtype in Haskell is the ability to write different instances for some type.因此,Haskell 中 newtype 的目的之一是能够为某种类型编写不同的实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM