8

所以我不断听到很多关于无点编程的信息,我决定做一个小实验来测试我对它的掌握程度。这涉及采用一个带尖的函数来计算一个数字的阶乘并将其转换为无点形式。我设法做到了,但是无点结果的可读性远低于有针对性的结果。

-- pointed
fact 0 = 1
fact n = n * (fact (n-1))
-- point free
fact' = foldr1 (*) . takeWhile ((<) 0) . iterate (flip (-) 1)

我是否遗漏了点自由符号所必需的东西,或者这是否像某些转换一样可读?对我来说,函数的很大一部分似乎fact是零上的模式匹配,事实上,模式匹配是我喜欢 Haskell 的最大原因之一。然而,无点符号似乎完全不允许这样做,以及其他一些非常有用的东西,比如列表推导。

4

2 回答 2

15

无点形式的规范阶乘是:

fact = product . enumFromTo 1

(相当于fact n = product [1..n]

我觉得这很有可读性。但是,我同意原始版本:

fact 0 = 1
fact n = n * (fact (n-1))

与定义非常匹配,并且可读性也很好。

无点形式的要点(哈!)是为了便于将函数推理为其他函数的组合。然而,阶乘函数并不是这种推理的最佳候选者。

很明显,决定权在你。

于 2012-07-19T03:17:45.873 回答
2

对于每个代数联合数据类型,都应该存在其类型大小写鉴别器函数,该函数封装了该类型的模式匹配。我们已经有了

either :: (a -> c) -> (b -> c) -> Either a b -> c
maybe :: b -> (a -> b) -> Maybe a -> b

同样,数字也必须有这样的功能,

num :: (Num a) => b -> (a -> b) -> a -> b
num z nz 0 = z
num z nz x = nz x

所以我们可以写

import Control.Applicative
import Data.Function

fact :: (Num a) => a -> a
fact x = num 1 (\x-> (*) (fact (pred x)) x) x
       = num 1 ((*) =<< (fact.pred)) x

IE

fact   = (num 1 . ((*) =<<) . (. pred)) fact
       = fix (num 1 . ((*) =<<) . (. pred)) 
于 2013-11-11T10:09:04.130 回答