Haskell使用“until”函数模拟[1 .. n]

问题描述:

我想模拟Haskell中的[1 .. n]功能,但使用until函数。我想要做这样的事情:Haskell使用“until”函数模拟[1 .. n]

seq :: Int -> [Int] 
seq a = until (\list -> if (length list) > a then True else False) (\x -> x ++ ((tail x) + 1)) [1] 

,并通过调用seq 5它应该返回[1, 2, 3, 4, 5]。我必须使用until函数。如果你愿意,这是一个限制。

+2

你的第一个lambda是过分复杂的。它可以简单地写成'(\ list - >(length list)> a)',或者完全用'((> a)。length)'来完成,尽管很多人可能会发现后者很难阅读。 – ApproachingDarknessFish

+2

'seq'对用户定义的函数来说是一个非常不恰当和令人困惑的名字:它也作为原始函数/运算符存在,用于强制评估其他懒惰的thunk。另外,不要使用“序列”,因为测序具有特殊而广泛的含义。 –

我认为这一个不错的解决方案是不尝试恢复“我们还需要做多少步骤”,从列表构建,而是使用until上的一对列表和数量添加剩余的元素:

     (5, []) -> 
(4, 5:[])   = (4, [5]) -> 
(3, 4:[5])   = (3, [4, 5]) -> 
(2, 3:[4, 5])  = (2, [3, 4, 5]) -> 
(1, 2:[3, 4, 5]) = (1, [2, 3, 4, 5]) -> 
(0, 1:[2, 3, 4, 5]) = (0, [1, 2, 3, 4, 5]) 

注意,当剩余元件的数量是0,即正好意味着我们已经构建列表是一个我们之后。

因此,我们可以实现这个想法通过做一个until了一对,检查是否对的第一个元素是等于0,以决定是否我们已经完成:

seq0 :: Int -> (Int, [Int]) 
seq0 n = until (\(i, is) -> i == 0) (\(i, is) -> (i-1, i:is)) (n, []) 

当然,这将返回全对(0, [1..n]),所以我们只需要保留一对的第二个元素:

seq :: Int -> [Int] 
seq n = snd (seq0 n) 
+0

谢谢!我发现如何解决这个问题:) –

感谢您的答复。我找到了解决它的另一种方法:

seq :: Int -> [Int]  
seq a = until (\l -> (length l) >= a) (\x -> x ++ [((last x) + 1)]) [1] 
+3

Dr.“Cactus”Erdi的方法既简单又高效。你应该研究它并思考为什么。 – dfeuer