我对函数式编程中使用的monad和箭头的概念非常熟悉.我也明白它们可以用来解决类似的问题.
但是,对于如何选择在任何给定情况下使用哪一个,我仍然有点困惑.
我什么时候应该使用monads?什么时候应该使用箭头?
language-agnostic monads haskell functional-programming arrows
我试着学习箭的含义,但我不理解它们.
我使用了Wikibooks教程.我认为Wikibook的问题主要在于它似乎是为那些已经理解了这个主题的人写的.
有人可以解释箭头是什么以及我如何使用它们?
我一直试图控制箭头,因为它们是大多数FRP实施的基础.我想我理解了它的基本思想 - 它们与monad有关但在每个绑定操作符中存储静态信息,因此您可以遍历一系列箭头并查看静态信息,而无需评估整个箭头.
但是,在我们开始讨论第一,第二和交换时,我迷路了.2元组与箭头有什么关系?教程提供了元组的东西,好像它是明显的下一步,但我并没有真正看到连接.
就此而言,箭头语法直观地意味着什么?
根据着名的论文,成语是不经意的,箭头是一丝不苟的,monad是混杂的,箭头的表达能力(没有任何额外的类型)应该在应用函子和monad之间严格地说:monads相当于ArrowApply
,并且Applicative
应该等同于纸张称为"静态箭头".但是,我不清楚这种"静态"意味着什么限制.
玩弄的问题有三种类型类,我是能够建立应用性函子和箭头,这是我在与知名等价的上下文中呈现之间的等价Monad
和ArrowApply
.这种结构是否正确?(我在厌倦之前证明了大部分的箭法).这是不是意味着Arrow
并且Applicative
完全一样?
{-# 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 …
Run Code Online (Sandbox Code Playgroud) 我们知道免费的monad是有用的,像Operational这样的包可以很容易地定义新的monad,只关注特定于应用程序的效果,而不是monadic结构本身.
我们可以很容易地定义"自由箭头",类似于如何定义自由单子:
{-# LANGUAGE GADTs #-}
module FreeA
( FreeA, effect
) where
import Prelude hiding ((.), id)
import Control.Category
import Control.Arrow
import Control.Applicative
import Data.Monoid
data FreeA eff a b where
Pure :: (a -> b) -> FreeA eff a b
Effect :: eff a b -> FreeA eff a b
Seq :: FreeA eff a b -> FreeA eff b c -> FreeA eff a c
Par :: FreeA eff a? b? -> FreeA eff a? …
Run Code Online (Sandbox Code Playgroud) 我现在对箭头机械的其余部分感到相当舒服,但我不知道循环是如何工作的.这对我来说似乎很神奇,这对我的理解不利.我也很难理解mfix.当我查看一个rec
在块proc
或do
块中使用的代码时,我感到困惑.使用常规的monadic或箭头代码,我可以逐步完成计算并保持头脑中正在发生的事情.当我到达时rec
,我不知道要保留什么图片!我卡住了,我无法推断这样的代码.
我试图解决的例子来自Ross Paterson关于箭头的论文,关于电路的论文.
counter :: ArrowCircuit a => a Bool Int
counter = proc reset -> do
rec output <- returnA -< if reset then 0 else next
next <- delay 0 -< output+1
returnA -< output
Run Code Online (Sandbox Code Playgroud)
我假设如果我理解这个例子,我将能够理解循环,这将是理解mfix的一个很好的方法.他们对我的感觉基本上是一样的,但也许我有一个微妙的缺失?无论如何,我真正想要的是这些代码片段的操作画面,所以我可以在头脑中像"常规"代码一样介绍它们.
编辑:感谢Pigworker的回答,我开始考虑rec和满足要求.取counter
实施例中,REC块的第一行需要一个叫做值output
.我想象这可以创建一个盒子,标记它output
,并要求rec块填充那个盒子.为了填充该框,我们为returnA提供一个值,但该值本身需要另一个值,称为next
.为了使用这个值,必须要求rec块中的另一行,但是现在要求在rec块中的哪个行并不重要.
所以我们转到下一行,我们发现标有框next
,我们要求另一个计算填充它.现在,这个计算需要我们的第一个盒子!所以我们给它一个盒子,但它里面没有任何价值,所以如果这个计算需要内容output
,我们就会遇到无限循环.幸运的是,延迟占用了盒子,但产生了一个值而没有查看盒子内部.这填补next
,然后允许我们填补output
.现在output
已经填充,当处理该电路的下一个输入时,前一个output
框将具有其值,准备被要求以产生下一个next …
所以我将我的问题分成4个部分,但首先是一些背景:
我对Monads感觉相对舒服,但对Arrows不太满意.我想我遇到的主要问题是,我看不出它们对它们有用.无论形式是否正确,我都理解Monads是一种工具,可以让我们从计算中引入副作用.因为它们将程序片段从纯值推广到用其他动作装箱的值.从我的霰弹枪"阅读所有论文"的方法来学习箭头,我遇到了两个相互矛盾的观点:
答:箭头比Monads更强大/是Monads的概括.haskell wiki的开头是"他们可以做monad所能做的一切,甚至更多.它们与具有静态组件的monad大致相当."
B.箭头是Monads的子集使用ArrowApply我们可以定义monad
在箭头符号中,您可以使用rec关键字来编写递归定义.例如:
rec
name <- function -< input
input <- otherFunction -< name
Run Code Online (Sandbox Code Playgroud)
这怎么能评估?它似乎只会进入一个无限循环或其他东西.我知道它评估循环箭头组合器,但我不明白它是如何工作的.
编辑:权力示例非常有用.但是你怎么用写符号来写呢?我假设你需要使用rec.
如果我们将对类别的理解限制Category
为Haskell中的常用类:
class Category c where
id :: c x x
(>>>) :: c x y -> c y z -> c x z
Run Code Online (Sandbox Code Playgroud)
那么让我们说a Arrow
是Category
另外一个:
class Category c => Arrow c where
(***) :: c x y -> c x' y' -> c (x,x') (y,y')
(&&&) :: c x y -> c x y' -> c x (y,y')
Run Code Online (Sandbox Code Playgroud)
我们可以很容易地推导出:
first :: c x y -> c (x,z) (y,z)
first a = a *** id
second …
Run Code Online (Sandbox Code Playgroud) 我正在创建一个ggplot
图表,我希望在两点之间有一些箭头.主要任务很容易完成geom_line(arrow = arrow())
.但是,我想要一些"漂亮"的粗箭.调整箭头的大小size=
没有用,因为它完全弄乱了箭头.我说明了我的问题:
创建一些示例数据和图:
NAME <- c("A", "A", "B", "B", "C", "C")
YEAR <- c(2016, 2011, 2016, 2011, 2016, 2011)
YEAR <- as.factor(YEAR)
VALUE <- c(1, 4, 1, 5, 2, 8)
DATA <- data.frame(NAME, YEAR, VALUE)
ggplot(DATA, aes(x=VALUE, y=NAME)) +
geom_point(size=5, aes(colour=YEAR)) +
geom_line(arrow = arrow(length=unit(0.30,"cm"), ends="first", type = "closed"))
Run Code Online (Sandbox Code Playgroud)
结果图看起来像这样:
现在我试图"加厚"箭头......
ggplot(DATA, aes(x=VALUE, y=NAME)) +
geom_point(size=5, aes(colour=YEAR)) +
geom_line(arrow = arrow(length=unit(0.30,"cm"), ends="first", type = "closed"), size = 3)
Run Code Online (Sandbox Code Playgroud)
这是这里显示的结果:
我的问题:有没有办法绘制一些"美丽的"粗箭?