haskell - 您介意在论坛中解释一下代码吗?

标签 haskell

import Control.Applicative
import Control.Arrow

filter ((&&) <$> (>2) <*> (<7)) [1..10]  
filter ((>2) &&& (<7) >>> uncurry (&&)) [1..10]

两者得到相同的结果!然而,这对我来说很难理解。有人能详细解释一下吗?

最佳答案

让我们从第二个开始,它更简单。我们这里有两个神秘的运算符,其类型如下:

(&&&) :: Arrow a => a b c -> a b c' -> a b (c, c')
(>>>) :: Category cat => cat a b -> cat b c -> cat a c

ArrowCategory类型类主要涉及行为类似于函数的事物,其中当然包括函数本身,这里的两个实例都是简单的 (->) 。因此,重写类型以使用它:

(&&&) :: (b -> c) -> (b -> c') -> (b -> (c, c'))
(>>>) :: (a -> b) -> (b -> c) -> (a -> c)

第二个与 (.) 的类型非常相似,熟悉的函数复合运算符;事实上,它们是相同的,只是参数交换了。第一个比较陌生,但类型再次告诉您需要知道的所有内容 - 它需要两个函数,两个函数都采用公共(public)类型的参数,并生成一个函数,该函数将两个函数的结果组合成一个元组。

因此,表达式 (>2) &&& (<7)接受一个数字并生成一对 Bool基于比较的值。然后将结果输入 uncurry (&&) ,只需要一对 Bool s 并将它们组合在一起。生成的谓词用于以通常的方式过滤列表。

<小时/>

第一个比较神秘。我们有两个神秘的运算符,它们具有以下类型:

(<$>) :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b

观察 (<$>) 的第二个参数在这种情况下是 (>2) ,其类型为 (Ord a, Num a) => a -> Bool ,而 (<$>) 的类型的参数类型为 f a 。它们如何兼容?

答案是,就像我们可以替换(->)一样对于 acat在早期的类型签名中,我们可以想到 a -> Bool(->) a Bool ,并替换((->) a)对于f 。因此,使用((->) t)重写类型。而是为了避免与其他类型变量 a 发生冲突:

(<$>) :: (a -> b) -> ((->) t) a -> ((->) t) b
(<*>) :: ((->) t) (a -> b) -> ((->) t) a -> ((->) t) b

现在,将内容恢复为正常的中缀形式:

(<$>) :: (a -> b) -> (t -> a) -> (t -> b)
(<*>) :: (t -> (a -> b)) -> (t -> a) -> (t -> b)

第一个结果是函数组合,正如您可以从类型中观察到的那样。第二个更复杂,但类型再次告诉您需要什么 - 它需要两个带有公共(public)类型参数的函数,一个生成一个函数,另一个生成一个传递给该函数的参数。换句话说,类似 \f g x -> f x (g x) 。 (这个函数也恰好在组合逻辑中被称为 S combinator,这是逻辑学家 Haskell Curry 广泛探索的一个主题,其名字无疑看起来很奇怪!)

(<$>)的组合和(<*>)有点“扩展”什么(<$>)单独执行,在这种情况下意味着采用一个带有两个参数的函数,两个具有公共(public)参数类型的函数,将单个值应用于后两个,然后将第一个函数应用于两个结果。所以((&&) <$> (>2) <*> (<7)) x简化为(&&) ((>2) x) ((<7) x) ,或使用正常的中缀样式, x > 2 && x < 7 。和以前一样,复合表达式用于以通常的方式过滤列表。

<小时/>

另外,请注意,虽然这两个函数在某种程度上都被混淆了,但一旦您习惯了所使用的运算符,它们实际上就很容易阅读。第一个抽象了对单个参数执行多项操作的复合表达式,而第二个是将事物与函数组合串在一起的标准“管道”样式的通用形式。

我个人实际上发现第一个完全可读。但我不希望大多数人同意!

关于haskell - 您介意在论坛中解释一下代码吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6287785/

相关文章:

algorithm - 在 Haskell 的列表推导中构建列表列表

haskell - 引用半群或幺半群

haskell - 为什么我不能让 `where` 在 Hspec 中工作

haskell - 为什么 ghci 不能打印整数的第一个排列的头部,计算 'selection-style' ?

haskell - 通过reflex-dom中的websockets检测关闭的服务器连接?

haskell - GHCi 是否不应用默认声明来解决类型歧义?

haskell 光泽 : render Picture to Bitmap

haskell - 控制线程退出haskell应用程序

haskell - 带有崩溃的 Haskell 程序的空 .prof 文件(在 Windows 上)

haskell - 如何使用 Monad 实现全局计数器?