Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 箭头与应用函子完全等价?_Haskell_Applicative_Arrows_Category Theory - Fatal编程技术网

Haskell 箭头与应用函子完全等价?

Haskell 箭头与应用函子完全等价?,haskell,applicative,arrows,category-theory,Haskell,Applicative,Arrows,Category Theory,根据这篇著名的论文,arrow(没有任何额外的类型类)的表达能力应该严格介于applicative functor和monad之间:monad相当于ArrowApply,而applicative应该相当于论文称之为“静态箭头”的东西。然而,我不清楚这种“静态”的限制意味着什么 在讨论这三个类型类时,我能够在应用函子和箭头之间建立一个等价关系,我在下面介绍Monad和ArrowApply之间众所周知的等价关系。这个结构正确吗?(在厌倦之前,我已经证明了其中的大部分)。这难道不意味着箭头和应用程序完

根据这篇著名的论文,arrow(没有任何额外的类型类)的表达能力应该严格介于applicative functor和monad之间:monad相当于
ArrowApply
,而
applicative
应该相当于论文称之为“静态箭头”的东西。然而,我不清楚这种“静态”的限制意味着什么

在讨论这三个类型类时,我能够在应用函子和箭头之间建立一个等价关系,我在下面介绍
Monad
ArrowApply
之间众所周知的等价关系。这个结构正确吗?(在厌倦之前,我已经证明了其中的大部分)。这难道不意味着
箭头
应用程序
完全相同吗

{-# LANGUAGE TupleSections, NoImplicitPrelude #-}
import Prelude (($), const, uncurry)

-- In the red corner, we have arrows, from the land of * -> * -> *
import Control.Category
import Control.Arrow hiding (Kleisli)

-- In the blue corner, we have applicative functors and monads,
-- the pride of * -> *
import Control.Applicative
import Control.Monad

-- Recall the well-known result that every monad yields an ArrowApply:
newtype Kleisli m a b = Kleisli{ runKleisli :: a -> m b}

instance (Monad m) => Category (Kleisli m) where
    id = Kleisli return
    Kleisli g . Kleisli f = Kleisli $ g <=< f

instance (Monad m) => Arrow (Kleisli m) where
    arr = Kleisli . (return .)
    first (Kleisli f) = Kleisli $ \(x, y) -> liftM (,y) (f x)

instance (Monad m) => ArrowApply (Kleisli m) where
    app = Kleisli $ \(Kleisli f, x) -> f x

-- Every arrow arr can be turned into an applicative functor
-- for any choice of origin o
newtype Arrplicative arr o a = Arrplicative{ runArrplicative :: arr o a }

instance (Arrow arr) => Functor (Arrplicative arr o) where
    fmap f = Arrplicative . (arr f .) . runArrplicative

instance (Arrow arr) => Applicative (Arrplicative arr o) where
    pure = Arrplicative . arr . const

    Arrplicative af <*> Arrplicative ax = Arrplicative $
        arr (uncurry ($)) . (af &&& ax)

-- Arrplicatives over ArrowApply are monads, even
instance (ArrowApply arr) => Monad (Arrplicative arr o) where
    return = pure
    Arrplicative ax >>= f =
        Arrplicative $ (ax >>> arr (runArrplicative . f)) &&& id >>> app

-- Every applicative functor f can be turned into an arrow??
newtype Applicarrow f a b = Applicarrow{ runApplicarrow :: f (a -> b) }

instance (Applicative f) => Category (Applicarrow f) where
    id = Applicarrow $ pure id
    Applicarrow g . Applicarrow f = Applicarrow $ (.) <$> g <*> f

instance (Applicative f) => Arrow (Applicarrow f) where
    arr = Applicarrow . pure
    first (Applicarrow f) = Applicarrow $ first <$> f
{-#语言元组,NoImplicitPrelude}
导入前奏曲(($),常量,未终止)
--在红色的角落里,我们有箭头,来自*->*->*
进口管制.类别
导入控制.箭头隐藏(Kleisli)
--在蓝色的角落,我们有应用函子和单子,
--骄傲的*->*
导入控制
进口管制
--回想一下众所周知的结果,即每个单子都会产生一个箭头Apply:
newtype Kleisli m a b=Kleisli{runKleisli::a->m b}
实例(Monad m)=>类别(Kleisli m),其中
id=Kleisli返回
克莱斯利g。Kleisli f=Kleisli$g箭头(Kleisli m)其中
arr=Kleisli。(返回。)
第一(Kleisli f)=Kleisli$\(x,y)->liftM(,y)(f x)
实例(Monad m)=>箭头应用(Kleisli m),其中
app=Kleisli$\(Kleisli f,x)->f x
--每个arrow arr都可以转化为一个应用函子
--对于任何来源的选择
新类型Arrplicative arr o a=Arrplicative{runArrplicative::arr o a}
实例(Arrow arr)=>函子(arreplicative arr o),其中
fmap f=复制的。(阿里夫)。运行复制
实例(箭头arr)=>应用程序(应用程序arr o),其中
纯=复制的。啊。常数
arreplicative af arreplicative ax=arreplicative$
arr(未到期($)。(af&ax)
--箭头上的应用程序甚至是单子
实例(箭头应用arr)=>Monad(arreplicative arr o),其中
返回=纯
A复制ax>>=f=
Arrplicative$(ax>>>arr(runArrplicative.f))&&id>>应用程序
--每个应用函子f都可以变成箭头??
newtype applicatorrow f a b=applicatorrow{runapplicatorrow::f(a->b)}
实例(应用程序f)=>类别(应用程序f),其中
id=应用程序箭头$pure id
应用箭头g。应用程序箭头f=应用程序箭头$(.)g f
实例(应用程序f)=>箭头(应用程序箭头f),其中
arr=应用箭头。纯净的
第一个(应用程序箭头f)=应用程序箭头$first f

每个应用程序都会生成一个箭头,每个箭头都会生成一个应用程序,但它们并不等价。如果您有一个箭头
arr
和一个态射
arrab
,那么并不意味着您可以生成一个复制其功能的态射
arro(a\to b)
。因此,如果您通过applicative来回访问,就会丢失一些特性

应用程序是幺半函子。箭头是profunctor,也是profunctor范畴中的范畴,或者等价地,是profunctor范畴中的幺半群。这两个概念之间没有天然的联系。请原谅我的轻率:在Hask中,箭头中的前函子的函子部分是一个幺半函子,但这种构造必然会忘记“前”部分

从箭头转到应用程序时,忽略了箭头中接受输入的部分,而只使用了处理输出的部分。许多有趣的箭头以这样或那样的方式使用输入部分,因此通过将它们转换为应用程序,您就放弃了有用的东西


这就是说,在实践中,我发现应用程序是一种更好的抽象,而且它几乎总是做我想做的事情。从理论上讲,箭的威力更大,但我发现自己并没有在实践中使用它们

让我们将IO应用函子与IO单子的Kleisli箭头进行比较

您可以使用一个箭头打印上一个箭头读取的值:

runKleisli ((Kleisli $ \() -> getLine) >>> Kleisli putStrLn) ()
但是你不能用应用函子。对于应用函子,所有效果都发生在将函子中的函数应用于函子中的参数之前。可以说,函子中的函数不能使用函子中参数内的值来“调节”其自身的效果。

(我已将下面的内容发布到,并提供了扩展的介绍)

Tom Ellis建议考虑一个涉及文件I/O的具体示例,因此让我们比较使用三个类型类的三种方法。为了简单起见,我们只关心两个操作:从文件中读取字符串和将字符串写入文件。文件将通过其文件路径进行标识:

type FilePath = String
一元I/O 我们的第一个I/O接口定义如下:

data IOM ∷ ⋆ → ⋆
instance Monad IOM
readFile ∷ FilePath → IOM String
writeFile ∷ FilePath → String → IOM ()
使用此接口,我们可以将文件从一个路径复制到另一个路径:

copy ∷ FilePath → FilePath → IOM ()
copy from to = readFile from >>= writeFile to
然而,我们可以做的远不止这些:我们操作的文件的选择可以取决于上游的效果。例如,下面的函数获取包含文件名的索引文件,并将其复制到给定的目标目录:

copyIndirect ∷ FilePath → FilePath → IOM ()
copyIndirect index target = do
    from ← readFile index
    copy from (target ⟨/⟩ to)
另一方面,这意味着无法预先知道将由给定值
操作操作的文件名集∷ IOMα
。我所说的“前期”是指编写纯函数
fileNames::IOMα的能力→ [文件路径]

当然,对于非基于IO的单子(例如我们有某种提取器函数
μα的单子)→ α
),这种区别变得有点模糊,但考虑在不评估单子效果的情况下提取信息仍然有意义(例如,我们可以问“我们对
了解多少?”
data IOF ∷ ⋆ → ⋆
instance Applicative IOF
readFile ∷ FilePath → IOF String
writeFile ∷ FilePath → String → IOF ()
writeFile′ ∷ FilePath → IOF (String → ())
copy ∷ FilePath → FilePath → IOF ()
copy from to = writeFile′ to ⟨*⟩ readFile from
(λ write → [write "foo", write "bar", write "foo"]) ⟨$⟩ writeFile′ "out.txt"
readFile ∷ Kleisli IOM FilePath String
writeFile ∷ Kleisli IOM (FilePath, String) ()
copyIndirect ∷ Kleisli IOM (FilePath, FilePath) ()
copyIndirect = proc (index, target) → do
    from ← readFile ↢ index
    s ← readFile ↢ from
    writeFile ↢ (to, s)
readFile ∷ FilePath → Applicarrow IOF () String
writeFile ∷ FilePath → String → Applicarrow IOF () ()
data IOA ∷ ⋆ → ⋆ → ⋆
instance Arrow IOA
readFile ∷ FilePath → IOA () String
writeFile ∷ FilePath → IOA String ()
copy ∷ FilePath → FilePath → IOA () ()
copy from to = readFile from >>> writeFile to