Applicative与Arrow

2024-02-29 06:58
文章标签 arrow applicative

本文主要是介绍Applicative与Arrow,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文说得非常清楚,不翻译效果可能更好。


进入ghci 

> :m + Control.Applicative Control.Arrow
Control.Applicative Control.Arrow>filter ((>2) &&& (<7) >>> uncurry (&&)) [1..10]
[3,4,5,6]


We have two mysterious operators here, with the following types:
(&&&) :: Arrow a => a b c -> a b c' -> a b (c, c')
(>>>) :: Category cat => cat a b -> cat b c -> cat a c

The Arrow and Category type classes are mostly about things that behave like functions, which of course includes functions themselves, and both instances here are just plain(->). So, rewriting the types to use that:
(&&&) :: (b -> c) -> (b -> c') -> (b -> (c, c'))
(>>>) :: (a -> b) -> (b -> c) -> (a -> c)

The second has a very similar type to (.), the familiar function composition operator; in fact, they're the same, just with arguments swapped. The first is more unfamiliar, but the types again tell you all you need to know--it takes two functions, both taking an argument of a common type, and produces a single function that gives the results from both combined into a tuple.

So, the expression (>2) &&& (<7) takes a single number and produces a pair of Bool values based on the comparisons. The result of this is then fed into uncurry (&&), which just takes a pair of Bools and ANDs them together. The resulting predicate is used to filter the list in the usual manner.


Control.Applicative Control.Arrow>filter ((&&) <$> (>2) <*> (<7)) [1..10]

[3,4,5,6]


We have two mysterious operators, again, with the following types:
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b

Observe that the second argument of (<$>) in this case is (>2), which has type (Ord a, Num a) => a -> Bool, while the type of (<$>)'s argument has type f a. How are these compatible?

The answer is that, just as we could substitute (->) for a and cat in the earlier type signatures, we can think of a -> Bool as (->) a Bool, and substitute((->) a) for the f. So, rewriting the types, using ((->) t) instead to avoid clashing with the other type variable a:
(<$>) :: (a -> b) -> ((->) t) a -> ((->) t) b
(<*>) :: ((->) t) (a -> b) -> ((->) t) a -> ((->) t) b

Now, putting things back in normal infix form:
(<$>) :: (a -> b) -> (t -> a) -> (t -> b)
(<*>) :: (t -> (a -> b)) -> (t -> a) -> (t -> b)

The first turns out to be function composition, as you can observe from the types. The second is more complicated, but once more the types tell you what you need--it takes two functions with an argument of a common type,one producing a function, the other producing an argument to pass to the function. In other words, something like \f g x -> f x (g x). (This function also happens to be known as the S combinator in combinatory logic, a subject explored extensively by the logician Haskell Curry, whose name no doubt seems strangely familiar!)

The combination of (<$>) and (<*>) sort of "extends" what (<$>) alone does, which in this case means taking a function with two arguments, two functions with a common argument type, applying a single value to the latter two, then applying the first function to the two results. So ((&&) <$> (>2) <*> (<7)) x simplifies to(&&) ((>2) x) ((<7) x), or using normal infix style, x > 2 && x < 7. As before, the compound expression is used to filter the list in the usual manner.

Also, note that while both functions are obfuscated to some degree, once you get used to the operators used, they're actually quite readable. The first abstracts over a compound expression doing multiple things to a single argument, while the second is a generalized form of the standard "pipeline" style of stringing things together with function composition.

Personally I actually find the first one perfectly readable. But I don't expect most people to agree!


总结

Applicatives are great when you've got a plain old function of several variables, and you have the arguments but they're wrapped up in some kind of context. For instance, you have the plain old concatenate function (++) but you want to apply it to 2 strings which were acquired through I/O. Then the fact that IO is an applicative functor comes to the rescue:

Prelude Control.Applicative> (++) <$> getLine <*> getLine 

hi
there
"hithere"


The basic idea is that you're "lifting" a regular function into a context where it can be applied to as many arguments as you like. The extra power of Applicative over just a basic Functor is that it can lift functions of arbitrary arity, whereas fmap can only lift a unary function.



这篇关于Applicative与Arrow的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/757924

相关文章

CocosCreator物理引擎Demo源码分析(3)-stick-arrow

CocosCreator开发笔记(8)-读取和解析JSON数据文件 Box2D C++ 三种作用力效果 ApplyForce、ApplyLinearImpulse、SetLinearVelocity stick-arrow示例展示了如何动态发射刚体飞往目标点。 技术点 1、触摸屏幕发射刚体,计算起点和目标点的夹角,设置刚体的线性速度。 2、在Update中不断施加一个作用力到刚体尾部

Apache Arrow简介

是什么? (1) Apache Arrow是内存分析开发平台,是Apache的顶级项目。 (2) Apache Arrow是一个开源的跨平台数据层开发框架,主要提供高效的、硬件加速的、内存中数据计算的能力。Apache Arrow的设计初衷是作为“新一代大数据系统的共享基础”,可以作为不同系统之间进行高效数据交换的媒介,同时提供快速、低延迟的数据访问接口。Apache Arrow的主要目标

基于 apache-arrow 的 duckdb rust 客户端

背景 duckdb 是一个 C++ 编写的单机版嵌入式分析型数据库。它刚开源的时候是对标 SQLite 的列存数据库,并提供与 SQLite 一样的易用性,编译成一个头文件和一个 cpp 文件就可以在程序中使用,甚至提供与 SQLite 兼容的接口,因此受到了很多人的关注。 本文介绍笔者近期开发的 duckdb-rs 库,让大家可以很方便地在 rust 代码库中使用 duckdb 的功能。 li

ES6新特性箭头函数(Arrow Function)

箭头函数是ECMAScript 6最受关注的更新内容之一。它引入了一种用「箭头」(=>)来定义函数的新语法,它…它碉堡了~。箭头函数与传统的JavaScript函数主要区别在于以下几点: 1.对 this 的关联。函数内置 this 的值,取决于箭头函数在哪儿定义,而非箭头函数执行的上下文环境。 2.new 不可用。箭头函数不能使用 new 关键字来实例化对象,不然会报错。 3.

Scalaz(7)- typeclass:Applicative-idomatic function application

Applicative,正如它的名称所示,就是FP模式的函数施用(function application)。我们在前面的讨论中不断提到FP模式的操作一般都在管道里进行的,因为FP的变量表达形式是这样的:F[A],即变量A是包嵌在F结构里的。Scalaz的Applicative typeclass提供了各种类型的函数施用(function application)和升格(lifting)方

引导页面的移动箭头效果 guide arrow animation

要实现类似效果 由于动画是非平滑的,所以不能用平移的方式来实现,这里就定时去更新在父布局的位置来是实现 先看布局代码 <RelativeLayoutandroid:id="@+id/swipe_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gr

HDU 1756 Cupid's Arrow 判断点在多边形的内部

Cupid's Arrow Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1163    Accepted Submission(s): 425 Problem Description 传说世上有一支丘比特的箭,凡是被这支箭射到的人

Cupid's Arrow

传说世上有一支丘比特的箭,凡是被这支箭射到的人,就会深深的爱上射箭的人。 世上无数人都曾经梦想得到这支箭。Lele当然也不例外。不过他想,在得到这支箭前,他总得先学会射箭。 日子一天天地过,Lele的箭术也越来越强,渐渐得,他不再满足于去射那圆形的靶子,他开始设计各种各样多边形的靶子。 不过,这样又出现了新的问题,由于长时间地练习射箭,Lele的视力已经高度近视,他现在甚至无法判断他的箭射到了靶子

HDU 1756 Cupid's Arrow(判断点是否在多边形内部)

Cupid's Arrow Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 702    Accepted Submission(s): 252 Problem Description 传说世上有一支丘比特的箭,凡是

arrow,一个神奇的 Python 库!

更多资料获取 📚 个人网站:ipengtao.com 大家好,今天为大家分享一个神奇的 Python 库 - arrow。 Github地址:https://github.com/arrow-py/arrow 日期和时间处理是许多应用程序中的常见任务,但在 Python 中,标准库中的 datetime 模块有时可能会让这些任务变得复杂和繁琐。幸运的是,有一个名为 Arrow 的