[英]Immutable data structures in F#
我正在尝试使用其内置的泛型类型在F#中实现非常琐碎的堆栈。 来自命令式范例,有时很难想象如何避免可变性。
到目前为止,我得到的是一个带有push和pop运算符的简单数据结构:
type Stack<'a> =
| Empty
| S of 'a list
with
member L.Push x =
match L with
| Empty | S ([]) -> S ([x])
| S (V) -> S (x :: V)
member L.Pop =
match L with
| Empty | S ([]) -> failwith "Error: Stack is empty"
| S (v::_) -> v
end
我的想法是使Stack持有S of 'a list
,我们用cons ::
运算符修改列表以不使列表S
突变,而是将其替换为S'
。 到目前为止,堆栈最多只能包含一个元素,并且将元素推入堆栈时不会增长-同样,弹出时也不会收缩。
谁能给我一个关于如何以不同的方式重写结构/思考的提示吗?
谢谢!
您可以通过简单地让列表充当堆栈来以更实用的方式执行此操作。 除了方法之外,您还可以使push
和pop
为函数。
// Returns the new stack
let push item stack = item :: stack
// Returns (item, newStack) tuple or throws if stack is empty
let pop stack =
match stack with
| [] -> failwith "Stack is empty"
| item :: newStack -> item, newStack
// Example usage
let stack = []
let populatedStack = push "hello" stack
// populatedStack = ["hello"]
let item, emptiedStack = pop populatedStack
// item = "hello"
// emptiedStack = []
内置的不可变列表已经是有效的Stack结构。 推送操作为::
,您将获得带有模式匹配的最后一项,例如let (first,rest) = list
如果要从头开始创建堆栈。 这里是一些实现。
1)
a)堆栈为空
b)或一个值和对先前堆栈的引用。
type Stack<'a> =
| Empty
| Value of 'a * Stack<'a>
module Stack =
let isEmpty = function
| Empty -> true
| Value _ -> false
let empty = Empty
let push x stack = Value (x, stack)
let pop (Value (x, stack)) = x, stack
let stk =
Stack.empty
|> Stack.push 1
|> Stack.push 2
|> Stack.push 3
let rec loop stack =
if Stack.isEmpty stack
then ()
else
let first, rest = Stack.pop stack
printfn "First: %d" first
loop rest
loop stk
您还可以选择一条记录作为基础数据结构。
type Stack<'a> = {
Value: 'a option
Next: Stack<'a> option
}
这样,具有三个元素的堆栈看起来像。
{Value=Some 3; Next=
{Value=Some 2; Next=
{Value=Some 1; Next=
{Value=None; Next=None}}}}
您还可以选择具有value
和next
字段的类,并为最后一个元素使用null
。
重要的是如何使用这些结构。 处理不可变数据结构的方法是使用递归函数而不是循环。
创建一个访问每个元素并在每个元素上执行一个函数的尾递归函数是fold
函数,相当于forEach
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.