我一直认为,一个无点函数的先决条件是将函数参数放到定义的末尾。例如。
-- 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)我最初看到的是这个问题。下面是一个例子:
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)那么,为什么我的第一个例子可以是无意义的,但其他两个不能呢?
发布于 2016-12-01 18:37:39
-但是这不能:让长z x=长度
mapx-让长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,那么省略(.)参数是很容易的:
agreeLen x y = (length . takeWhile id . zipWith (==) x) y
agreeLen x = length . takeWhile id . zipWith (==) x至于x,我们可以通过使用(.)将zipWith (==) x与其他函数组合为另一种用函数修改值的情况来处理:
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 (==)在实践中,这并不是你真正想要做的事情,但这当然是可能的。
发布于 2016-12-01 18:37:29
您的第一个版本可以使用无点样式编写,但您必须将其调整为使用map作为infix函数。
let lengthz = (length `map`) -- write the partial application as a sectionagreeLen的问题是,zipWith不是一个参数的函数,而是两个参数的函数。zipWith需要应用于两个参数,然后才能将其结果传递给takeWhile id。用无点样式编写它的不容易的方法是
-- via http://pointfree.io
agreeLen = ((length . takeWhile id) .) . zipWith (==)简单地说,zipWith (==)应用于agreeLen的第一个参数x以生成一个新函数(一个接受列表并返回压缩列表的函数)。这个新函数作为(length . takeWhile id) .的一个参数,它生成一个新的组合函数,该函数将第二个参数接受到agreeLen并生成所需的Int值。
(@duplode 导出此可能比我要尝试的更干净。)
当初始函数使用两个以上的参数时,一个很快就失控的技巧是显式地取消它,进行组合,然后重新修改结果。
agreeLen = curry $ length . takeWhile id . (uncurry $ zipWith (==))发布于 2016-12-01 20:26:55
如果我们称这种形式的函数定义为无点的。
f = e如果f只是一个函数名,而e是一个表达式,那么我们至少可以使这些函数没有任何点。
也就是说,如果这些参数只是简单的名称,那么如果其他两个条件也得到满足,我们就可以使其无意义。
对于需要某些模式匹配的参数,如果我们能够消除带有某些函数(如maybe、either、fst、snd)的构造函数,我们通常可以重写该函数,从而得到一个可以编写无点的函数:
f (a,b) = (b,a)
f' ab = (snd ab, fst ab)
f'' = (pure (,) <*> snd) <*> fst另外,右边的if表达式可以重写为bool的应用程序。
下面是一个算法,它消除了表达式e中的一些变量v,这样得到的表达式x不包含v,并且当应用于v时等于e。
pure eid。下面是如何使函数定义为零,以满足上述需求。
f v1 v2 v3 ... vn = e注意,有不同的方法可以消除使用诸如(.) flip等函数的表达式的变量形式,这些方法通常导致代码更短,但是,上面的方法是最基本的方法,因为它只需要S、K和I组合子(它们是在Haskell中编写的<*> pure和id )。
https://stackoverflow.com/questions/40917772
复制相似问题