无点表示法、递归和模式匹配



所以我一直听到很多关于无点编程的消息,我决定做一个小实验来测试我对它的理解。这包括使用一个有点函数来计算一个数字的阶乘,并将其转换为无点形式。我设法做到了,但无点结果的可读性比有点结果差得多。

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

我是不是错过了无点表示法的一些重要内容,或者这和某些转换一样可读?对我来说,fact函数的很大一部分似乎是零上的模式匹配,事实上,模式匹配是我喜欢Haskell的最大原因之一。然而,无点表示法似乎完全不允许这样做,还有其他一些非常有用的东西,比如列表理解。

无点形式的标准阶乘是:

fact = product . enumFromTo 1

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

我觉得这很可读。然而,我同意最初的版本:

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

与定义非常匹配,而且可读性强。

无点形式的要点(ha!)是使人们能够很容易地将函数作为其他函数的组成进行推理。然而,阶乘函数并不是这种推理的一个很好的候选者。

显然,决定权在你。

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

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)) 

最新更新