首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Haskell中,无点函数的先决条件是什么?

在Haskell中,无点函数的先决条件是什么?
EN

Stack Overflow用户
提问于 2016-12-01 18:23:09
回答 3查看 1.1K关注 0票数 4

我一直认为,一个无点函数的先决条件是将函数参数放到定义的末尾。例如。

代码语言:javascript
复制
-- This can be made pointfree quite easily:    
let lengths x = map length x    
let lengths' = map length

-- However this cannot:
let lengthz x = length `map` x
-- let lengthz' = length `map` (parse error)

我最初看到的是这个问题。下面是一个例子:

代码语言:javascript
复制
agreeLen :: (Eq a) => [a] -> [a] -> Int
agreeLen x y = length $ takeWhile id $ zipWith (==) x y
-- This may look like it can easily be made pointfree, however it cannot
-- agreeLen' :: (Eq a) => [a] -> [a] -> Int
-- agreeLen' = length $ takeWhile id $ zipWith (==) (zipWith is applied to too few arguments)

那么,为什么我的第一个例子可以是无意义的,但其他两个不能呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-12-01 18:37:39

-但是这不能:让长z x=长度map x-让长z‘=长度map (解析错误)

\x -> length `map` x写的无点就是简单的map length。后背只是语法上的糖。(正如切普纳所指出的,如果你真的想要它,你可以使用一个部分,即(length `map`)。)

agreeLen ::(Eq ) => a -> a -> Int agreeLen x y= length $ takeWhile id $ zipWith (==) x-这看起来很容易就可以使其无意义,但是它不能。

这里的关键词是“容易”。如果你努力的话,几乎所有的东西都可以变成无积分的。在这种情况下,如果我们用y而不是($)来编写agreeLen,那么省略(.)参数是很容易的:

代码语言:javascript
复制
agreeLen x y = (length . takeWhile id . zipWith (==) x) y
agreeLen x = length . takeWhile id . zipWith (==) x

至于x,我们可以通过使用(.)zipWith (==) x与其他函数组合为另一种用函数修改值的情况来处理:

代码语言:javascript
复制
agreeLen x = (.) (length . takeWhile id) (zipWith (==) x)
agreeLen x = ((length . takeWhile id) .) (zipWith (==) x) -- cosmetical change
agreeLen x = (((length . takeWhile id) .) . zipWith (==)) x
agreeLen = ((length . takeWhile id) .) . zipWith (==)

在实践中,这并不是你真正想要做的事情,但这当然是可能的。

票数 7
EN

Stack Overflow用户

发布于 2016-12-01 18:37:29

您的第一个版本可以使用无点样式编写,但您必须将其调整为使用map作为infix函数。

代码语言:javascript
复制
let lengthz = (length `map`) -- write the partial application as a section

agreeLen的问题是,zipWith不是一个参数的函数,而是两个参数的函数。zipWith需要应用于两个参数,然后才能将其结果传递给takeWhile id。用无点样式编写它的不容易的方法是

代码语言:javascript
复制
-- via http://pointfree.io
agreeLen = ((length . takeWhile id) .) . zipWith (==)

简单地说,zipWith (==)应用于agreeLen的第一个参数x以生成一个新函数(一个接受列表并返回压缩列表的函数)。这个新函数作为(length . takeWhile id) .的一个参数,它生成一个新的组合函数,该函数将第二个参数接受到agreeLen并生成所需的Int值。

(@duplode 导出此可能比我要尝试的更干净。)

当初始函数使用两个以上的参数时,一个很快就失控的技巧是显式地取消它,进行组合,然后重新修改结果。

代码语言:javascript
复制
agreeLen = curry $ length . takeWhile id . (uncurry $ zipWith (==))
票数 6
EN

Stack Overflow用户

发布于 2016-12-01 20:26:55

如果我们称这种形式的函数定义为无点的。

代码语言:javascript
复制
f = e

如果f只是一个函数名,而e是一个表达式,那么我们至少可以使这些函数没有任何点。

  1. 有一个右手边,这只是一个函数应用程序。
  2. 不需要对它们的参数进行模式匹配
  3. 在“复杂”子表达式(如列表理解、案例、let或lambda抽象)中没有提到这些参数。

也就是说,如果这些参数只是简单的名称,那么如果其他两个条件也得到满足,我们就可以使其无意义。

对于需要某些模式匹配的参数,如果我们能够消除带有某些函数(如maybeeitherfstsnd)的构造函数,我们通常可以重写该函数,从而得到一个可以编写无点的函数:

代码语言:javascript
复制
 f (a,b) = (b,a)
 f' ab   = (snd ab, fst ab)
 f'' = (pure (,) <*> snd) <*> fst

另外,右边的if表达式可以重写为bool的应用程序。

下面是一个算法,它消除了表达式e中的一些变量v,这样得到的表达式x不包含v,并且当应用于v时等于e。

  • 如果e不包含v,则结果是pure e
  • 如果e为v,则结果为id
  • 如果e是应用于v的表达式f,而f没有提到v,则结果是f。
  • 否则,e必须是应用程序g,其中至少有一个g和h提到v。结果是g‘<*> h’,其中g‘是从g中消除v时产生的表达式,h是从h中消除v时产生的表达式。

下面是如何使函数定义为零,以满足上述需求。

代码语言:javascript
复制
 f v1 v2 v3 ... vn = e
  • 让e‘从e中消除vn
  • 写下新函数 v1 v2 v3 ..。v(n-1) = e‘
  • 如果没有争论,你就完蛋了
  • 否则,使f‘无点。

注意,有不同的方法可以消除使用诸如(.) flip等函数的表达式的变量形式,这些方法通常导致代码更短,但是,上面的方法是最基本的方法,因为它只需要S、K和I组合子(它们是在Haskell中编写的<*> pureid )。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40917772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档