我正在自学 Haskell。我有以下代码使用列表实现堆栈:
push :: Int -> [Int] -> [Int]
push x [] = [x]
push x xs = xs ++ [x]
pop :: [Int] -> [Int]
pop [] = error "Cannot pop from an empty list!"
pop xs = init xs
peek :: [Int] -> Int
peek [] = error "Cannot peek from an empty list!"
peek xs = last xs
isEmpty :: [Int] -> Bool
isEmpty [] = True
isEmpty xs = False
现在我想创建一个函数来遍历整数列表并在堆栈上执行以下操作:
例如,假设我们有一个整数 [0,2,6,7,3,4]
输入列表。函数的流程应该是这样的:
Current Int Operation Result
0 (First item) push 0 [] [0]
2 push 2 [0] [0, 2]
6 push 6 [0, 2] [0, 2, 6]
7 pop [0, 2, 6] [0, 2]
3 pop [0, 2] [0]
4 (Last item) push 4 [0] [0, 4]
这是我到目前为止所得到的,显然它没有遍历列表并且实际上不起作用:
operation :: [Int] -> [Int]
operation [] = []
operation (x:xs) | even x = push x stack
| odd x = pop stack
where stack = []
非常感谢您的帮助。提前致谢!
答案 0 :(得分:2)
使用您的代码,使用 foldl
实现这一点是最简单的。
operation :: [Int] -> [Int]
operation = foldl step []
where step xs x | odd x = pop xs
| otherwise = push x xs
但是,应该注意的是,您对堆栈的实现会使这些 pop
和 push
函数变慢。由于 Haskell 列表是单链表,您必须遍历整个列表才能到达最后的值。只操作列表头部的值,然后在整个操作完成时反转列表会更有效率。这会将您的 O(n2) 操作变成 O(n)。
pop = tail
push = (:)
operation :: [Int] -> [Int]
operation = reverse . foldl step []
where step xs x | odd x = pop xs
| otherwise = push x xs
还需要注意的是,这个函数仍然不安全,因为如果odd
数过多,操作可能会产生错误。最好使用 Maybe
来阻止任何错误。
import Control.Monad (foldM)
pop :: [a] -> Maybe [a]
pop [] = Nothing
pop (_:xs) = Just xs
push :: a -> [a] -> [a]
push = (:)
operation :: [Int] -> Maybe [Int]
operation = fmap reverse . foldM step []
where step xs x | odd x = pop xs
| otherwise = Just (push x xs)