我正在尝试实现函数tails
。这是我的尝试:
tails' :: [a] -> [[a]]
tails' [] = []
tails' (x:xs) = xs:[[tails' xs]]
我一直遇到编译错误:
Couldn't match expected type ‘a’ with actual type ‘[[a]]’
‘a’ is a rigid type variable bound by
the type signature for tails' :: [a] -> [[a]] at..
我的实施有什么问题?
答案 0 :(得分:5)
替换
tails' (x:xs) = xs:[[tails' xs]]
使用:
tails' (x:xs) = xs : tails' xs
答案 1 :(得分:4)
除了语法类型错误之外,您的实现不正确(对于规范)。将它与此相比......
Prelude> let tails [] = [[]]
Prelude| tails y@(x:xs) = y:(tails xs)
Prelude|
Prelude> tails "abc"
["abc","bc","c",""]
答案 2 :(得分:2)
由于现在有一个 recursion-schemes 折叠答案,我觉得有必要添加一个递归方案展开的答案:
import Data.Functor.Foldable
tailsApo :: [a] -> [[a]]
tailsApo = apo coalgTails
where
coalgTails = \case
[] -> Cons [] (Left [])
li@(_:xs) -> Cons li (Right xs)
我使用了一个apomorphism而不是一个简单的anamorphism,因为我们不想从空列表中生成一个空列表(tails [] == [[]]
)。
答案 3 :(得分:1)
现在已经过了一年多了,但没有给出正确的答案,所以这是我对它的看法。
让我们从类型签名开始:
tails' :: [a] -> [[a]]
这假设tails'
应该返回列表列表。你syggested的终端案例只是一个空列表。将其更改为:
tails' [] = [[]]
现在,一般情况。让假设我们的tails'
按照我们想要的方式运作:
tails' [] -> [[]]
tails' [1] -> [[1], []]
tails' [2,1] -> [[2,1], [1], []]
tails' [3,2,1] -> [[3,2,1], [2,1], [1], []]
我们可以看到,我们想要包含原始列表和空列表。这意味着给定输入列表xs
,我们希望将xs
连接到其他。
但其他什么是什么?让我们做一些伪haskell数学:
let A = tails' [3,2,1] = [[3,2,1], [2,1], [1], []]
let B = tails' [2,1] = [[2,1], [1], []]
=> A = [[3,2,1], B] -- (1)
tail [3,2,1] == [2,1]
=> B = tails' (tail [3,2,1]) -- (2)
By (1) and (2)
A = [[3,2,1], tails' (tail [3,2,1])]
=> tails' [3,2,1] = [[3,2,1], tails' (tail [3,2,1])] -- (3)
By replacing [3,2,1] in (3) with xs
tails' xs = [xs, tails' (tail xs)]
将所有这些翻译成Haskell给了我们:
tails' :: [a] -> [[a]]
tails' [] = [[]]
tails' xs = xs : (tails' $ tail xs)
main = do
print $ tails' [1,2,3]
-- [[1,2,3],[2,3],[3],[]]
答案 4 :(得分:1)
tails
是带有名为 paramorphism 的递归方案的简单列表的规范示例。以下示例使用Edward Kmett的recursion-schemes库:
import Data.Functor.Foldable
import Data.List (tails) -- just for our test
paratails :: [a] -> [[a]]
paratails = para alg where
alg :: ListF a ([a], [[a]]) -> [[a]]
alg (Cons x (hs, res)) = (x : hs) : res
alg Nil = [[]]
-- $
-- >>> paratails [1,2,3,4]
-- [[1,2,3,4],[2,3,4],[3,4],[4],[]]
-- >>> paratails []
-- [[]]
-- >>> paratails [1,2,3,4] == (tails [1,2,3,4])
-- True
-- >>> paratails [] == (tails [])
-- True
注意:要缩短代码,您可以使用 LambdaCase 。但是,使用此扩展名,您无法指定 alg 函数的类型签名