[英]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.