在Haskell中实现tails函数

时间:2017-01-03 16:57:37

标签: haskell

我正在尝试实现函数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..

我的实施有什么问题?

5 个答案:

答案 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 函数的类型签名