所以我一直听到很多关于点免费编程的知识,我决定做一些实验来测试我对它的掌握程度。这涉及采用有针对性的函数来计算数字的阶乘并将其转换为无点形式。我设法做到了,但是无点结果的可读性远远低于尖锐的结果。
-- pointed
fact 0 = 1
fact n = n * (fact (n-1))
-- point free
fact' = foldr1 (*) . takeWhile ((<) 0) . iterate (flip (-) 1)
我是否遗漏了指向自由符号所必需的东西,或者这是否像某些转换一样可读?对我而言,似乎fact
函数的很大一部分是零上的模式匹配,实际上,模式匹配是我喜欢Haskell的最大原因之一。然而,无点符号似乎完全不允许这一点,以及其他一些非常有用的东西,如列表推导。
答案 0 :(得分:15)
无点形式的规范因子是:
fact = product . enumFromTo 1
(相当于fact n = product [1..n]
)
我觉得这很可读。但是,我会同意原始版本:
fact 0 = 1
fact n = n * (fact (n-1))
很好地匹配定义,也是可读的。
无点形式的要点(ha!)是为了便于将函数推理为其他函数的组合。然而,阶乘函数并不是这种推理的理想选择。
显然,这个决定是你的。
答案 1 :(得分: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
即
fact = (num 1 . ((*) =<<) . (. pred)) fact
= fix (num 1 . ((*) =<<) . (. pred))