哈斯克尔应用型变压器的例子(Examples of Haskell Applicative Tran

2019-07-31 22:37发布

在www.haskell.org维基告诉我们以下有关应用型变压器:

那么,是合用的变压器? 答案是,我们并不需要对应用性函子特种变压器,因为它们可以在一个通用的方式进行组合。 http://www.haskell.org/haskellwiki/Applicative_functor#Applicative_transfomers

我想,以尽量一堆应用性函子的结合以下。 但是,所有我得到的是一堆错误。 下面是代码:

import Control.Applicative
import System.IO

ex x y = (:) <$> x <*> y 
test1 = ex "abc" ["pqr", "xyz"]  -- only this works correctly as expected
test2 = ex "abc" [Just "pqr", Just "xyz"]
test3 = ex "abc" (Just "pqr")
test4 = ex (Just 'a') ["pqr", "xyz"]
test5 = ex (return ("abc"):: IO ()) [Just "pqr", Just "xyz"]

这就产生了很多类型的错误,虽然我能理解一部分,我不可能解决这些根本的。

错误是在末尾。

所以,我怎么结合也许应用型和应用型列出例如?

如何结合国家应用型和应用型列出例如? 是否还有其他的例子,让我们说,也许合并和列表,也许和国家,最后是可怕的所有IO和国家applicatives的?

谢谢。

该GHCI错误封邮件跟进。

example.hs:6:19:
    Couldn't match expected type `[Char]' with actual type `Maybe a0'
    In the return type of a call of `Just'
    In the expression: Just "pqr"
    In the second argument of `ex', namely `[Just "pqr", Just "xyz"]'

example.hs:7:19:
    Couldn't match expected type `[[Char]]' with actual type `Maybe a0'
    In the return type of a call of `Just'
    In the second argument of `ex', namely `(Just "pqr")'
    In the expression: ex "abc" (Just "pqr")

example.hs:8:23:
    Couldn't match expected type `Maybe' with actual type `[]'
    In the second argument of `ex', namely `["pqr", "xyz"]'
    In the expression: ex (Just 'a') ["pqr", "xyz"]
    In an equation for `test4': test4 = ex (Just 'a') ["pqr", "xyz"]

example.hs:9:21:
    Couldn't match expected type `()' with actual type `[Char]'
    In the first argument of `return', namely `("abc")'
    In the first argument of `ex', namely `(return ("abc") :: IO ())'
    In the expression:
      ex (return ("abc") :: IO ()) [Just "pqr", Just "xyz"]
Failed, modules loaded: none.
Prelude>

Answer 1:

维基文章说, liftA2 (<*>)可以用来构成应用性仿函数。 它很容易地看到如何从它的类型使用它:

o :: (Applicative f, Applicative f1) =>
     f (f1 (a -> b)) -> f (f1 a) -> f (f1 b)
o = liftA2 (<*>)

所以,如果fMaybef1[]我们得到:

> Just [(+1),(+6)] `o` Just [1, 6] 
Just [2,7,7,12]

另一种方法是左右:

>  [Just (+1),Just (+6)] `o` [Just 1, Just 6]
[Just 2,Just 7,Just 7,Just 12]

正如@McCann说你的前妻功能相当于liftA2 (:)

test1 = liftA2 (:) "abc" ["pqr", "xyz"]

要使用(:)更深层次的应用性堆栈需要的多种应用liftA2

*Main> (liftA2 . liftA2) (:) (Just "abc") (Just ["pqr", "xyz"])
Just ["apqr","axyz","bpqr","bxyz","cpqr","cxyz"]

然而,只有当两个操作数都同样深刻的作品。 因此,除了双liftA2你应该使用pure固定的水平:

*Main> (liftA2 . liftA2) (:) (pure "abc") (Just ["pqr", "xyz"])
Just ["apqr","axyz","bpqr","bxyz","cpqr","cxyz"]


Answer 2:

考虑以下类型签名:

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

相结合,所得到的类型是:

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

这确实是两种组合Applicative秒。 事实上,它是整整两个组合Applicative秒。 换句话说,尽管你可以结合Applicative的通用方式S,这不是自动完成的任何方式。 一切都必须明确取消的正确次数。

您的ex函数等效于liftA2 (:) ,其具有类型(Applicative f) => fa -> f [a] -> f [a] 通过你的例子去,做你想做的事了一些猜测:

test1 = ex "abc" ["pqr", "xyz"]

这里f[]而我们把它应用到类型的参数[Char][[Char]]

test2 = ex "abc" [Just "pqr", Just "xyz"]

第二个参数是类型[Maybe [Char]] ,所以我们需要解除两次。 第一个参数也需要提升,因为它已键入[Char] ,应该是[Maybe Char]

test3 = ex "abc" (Just "pqr")

这一次的第二个参数的类型为Maybe [Char] ,所以fMaybe ,我们只需要一个电梯。 因此,第一个参数应该是类型Maybe Char

test4 = ex (Just 'a') ["pqr", "xyz"]

这一次的第一个参数是Maybe Char ,但第二个是[[Char]] ,所以你有两个完全不同的Applicative S; 双方将需要提升,让你无论是[Maybe Char]Maybe [Char]

test5 = ex (return ("abc"):: IO ()) [Just "pqr", Just "xyz"]

这里的类型签名是没有意义的; 你可能想IO [Char] 。 第二个参数的类型为[Maybe [Char]] 。 前面的例子,他们不匹配,但这个时候和你一样有三个 Applicative秒。 如果你想要像IO [Maybe a] ,你需要解除(:)所有三次,如liftA2 (liftA2 ex)

结合这种方式Applicative s的称为“函子组成”,和你链接到网页提到定义一个明确的组成类型的构造函数库。 例如, 使用transformers库 ,你可以有一个像型Compose IO (Compose [] Maybe)来形容你的第五例。 这种由类型被定义为一个Applicative在上述通用的方式实例,并应用吊装作业的正确数目。 缺点是,你需要包装和解开的newtype这需要层。


作为附录,这种说法:

那么,是合用的变压器? 答案是,我们并不需要对应用性函子特种变压器,因为它们可以在一个通用的方式进行组合。

...有点假。 这是真的,两个组成Applicative s是也Applicative ,但这不是结合的唯一途径Applicative小号!

考虑StateT sma ,这相当于s -> m (s, a)尽管它的定义略有不同。 这也可以写成三个函子组成: ((->) s) m ,和((,) s)并将得到的Functor实例将是正确的,但Applicative实例将是完全错误的。 如果你开始只是State sa = s -> (a, s)代替,没有办法定义StateT sm通过组合State sm

现在,观察到非组合物组合StateT s (Either e)实质上是在像秒差距库所使用的典型的解析器组合单子的简化版本,并且这种解析器是公知的地方使用的一个Applicative风格是受欢迎。 因此,它似乎比有点误导表明单子转换风格的组合都弄好了不必要的或多余的地方Applicative关注!



Answer 3:

说他们可以在一个通用的方式进行组合并不意味着他们可以隐式或无形之类的东西结合起来。 =)

你还需要的代码,或者通过使用不同的mungers比写位<*>pure或通过加入一些NEWTYPE噪声。 例如,使用TypeCompose包,你可以写

test2 = ex (O (Just "abc")) [O (Just "pqr"), O (Just "xyz")]


Answer 4:

像往常一样,它把重点放在类型弄清楚什么应用性函子的组成应该意味着这里是有用的。

如果我们写a特定的纯价值型x ,即因此没有副作用,那么我们就可以在这个纯粹的价值提升到适用函子的计算f使用pure组合子。 但是,同样的道理,我们可以使用pure从功能gApplicative实例,以提升pure xg仿函数。

pure (pure x) :: g (f a)

现在g (fa)是结合的效果的计算的类型g和的效果f 。 看你的测试中,我们注意到,

test1 :: [String]

您只使用了一个有效test1 ,那就是不确定性是列表中的实例Applicative给你。 事实上,它分解:

"abc" :: String
((:) <$>) :: [Char] -> [String -> String]
((:) <$> "abc") :: [String -> String]
((:) <$> "abc" <*> ["pqr", "xyz"]) :: [String]

现在,如果我们想组成失败效应和非确定性效应,我们希望构建类型的计算Maybe [a]或者[Maybe a] 。 事实证明,这两者是等价的,因为应用性仿函数总是下班

下面是类型的计算[Maybe Char] 。 它将非deterministally返回一个Char ,但如果这样做,可能会失败:

x1 = [Just 'a', Just 'b', Just 'c']

同样,这里的类型的计算[Maybe String]

x2 = [Just "pqr", Just "xyz"]

现在,我们要解除(:)这个组合适用函子。 要做到这一点,我们不得不提起它两次:

pure (pure (:)) :: [Maybe (Char -> String -> String)]

同样,应用它,我们需要通过两个函子来推动这个计算。 因此,我们可以引入一个新的组合子(<<*>>)做的是:

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

现在让我们来写:

pure (pure (:)) <<*>> x1 <<*>> x2

您可以检查有预期的类型。

但是,由于应用性仿函数下的组合物封闭, [Maybe a]本身是一个适用函子,所以你可能希望能够重用pure(<*>)Data.Functor.Compose的模块变压器包告诉您如何。



文章来源: Examples of Haskell Applicative Transformers