一个函数如何将一个函数的输出作为另一个函数的输入。
例如,我有这两个功能
collatz :: (Integral a) => a -> [a]
collatz 1 = [1]
collatz n
|even n = n:collatz (n `div` 2)
|odd n = n:collatz (n*3 + 1)
还有我的另一个功能
length' [] = 0
length' (x:xs) = 1 + length' xs
我想计算列表的长度,该列表是从collatz函数输出的。
最后我要完全计算
numLongChains :: Int
numLongChains = length (filter isLong (map collatz [1..100]))
where isLong xs = length xs > 15
但是要一步一步来
答案 0 :(得分:5)
您正在谈论function composition:
-- assuming signature length' :: [a] -> Int
composed :: (Integral a) => a -> Int
composed = length' . collatz
我不确定“一步一步”是什么意思,但是对于第二个问题,它将是:
numLongChains :: (Integral a) => [a] -> Int
numLongChains = length' . (filter isLong) . (map collatz)
where isLong xs = length' xs > 15
我将其设为一元函数,因此它可以与任何列表一起使用,而不仅限于[1..100]
。
答案 1 :(得分:2)
length'
的{{1}}序列中的collatz
是n
。这种模式非常普遍,我们给它起了一个名字:\n -> length' (collatz n)
。我们称其为“功能组合”。用f . g = \x -> f (g x)
,f
和g
替换上面的x
,length'
和collatz
,我们得到n
。所以:
length' . collatz = \n -> length' (collatz n)
顺便说一句,除了以一种不太明显的方式,我们也可以在此处使用函数组合,而不是像您那样写collatzLength = length' . collatz
:
isLong
因此,问题“ n的collatz序列长于15吗?”现在可以写成:
isLong xs = length' xs > 15
isLong = \xs -> length' xs > 15
isLong = \xs -> (>) (length' xs) 15
isLong = \xs -> (> 15) (length' xs) -- this is the less obvious bit
isLong = (> 15) . length'
所以数字isLongSequence = isLong . collatz
的长序列是
[1..100]
或搭配
filter isLongSequence [1..100]
是
longSequences = filter isLongSequence
现在,我们可以将longSequences [1..100]
写为
numLongChains
长链的数量是长序列(列表)的数量(长度)。
现在,要证明这与您的定义相同,您需要了解有关map和filter的规则(定理):
numLongChains = length' . longSequences
所以
filter p . map f = filter (p . f)
与
相同\xs -> filter isLong (map collatz xs)
与
相同filter isLong . map collatz
与
相同filter (isLong . collatz)
与
相同filter isLongSequence