Haskell 中列表实现中的变量重新分配
Variable re-assignment in an implementation of a list in Haskell
我按照大学课程的说明实现了二叉树(注意:请注意通常的二叉树,它是一种不同的算法,但这并不重要)
在我的 set 函数 set :: Eq a => SparseArray a -> Int -> a -> SparseArray a
中,如果我使用它来更新节点的值,该函数将做的是复制一个值已更改的树,而不是像预期的那样更新值。
我认为这就像在 return 语句中使用 let ... in
符号一样简单,但程序需要能够更改任何变量。
当然必须有一个解决方案,与 Haskell 中实现列表的方式相同。
data Value a = Null | Value a
deriving (Eq,Read,Show)
data SparseArray a = Vacio | Nodo (Value a) (SparseArray a) (SparseArray a)
deriving (Eq,Read,Show)
set :: Eq a => SparseArray a -> Int -> a -> SparseArray a
set Vacio index x = Nodo (Value x) (Vacio) (Vacio)
set (Nodo n iz de) index x
| index < 0 = Nodo n iz de
| length(num2bin(index)) == 0 = Nodo (Value x) (iz) (de)
| head(num2bin(index)) == False && ((Nodo n iz de) == Vacio) = Nodo (Null) (setL (iz) (tail(num2bin(index))) (x)) (de)
| head(num2bin(index)) == True && ((Nodo n iz de) == Vacio) = Nodo (Null) (iz) (setL (de) (tail(num2bin(index))) (x))
| head(num2bin(index)) == False = Nodo (n) (setL (iz) (tail(num2bin(index))) (x)) (de)
| head(num2bin(index)) == True = Nodo (n) (iz) (setL (de) (tail(num2bin(index))) (x))
where setL :: Eq a => SparseArray a -> [Bool] -> a -> SparseArray a
setL Vacio index x = Nodo (Value x) (Vacio) (Vacio)
setL (Nodo n iz de) index x
| length(index) < 0 = Nodo n iz de
| length(index) == 0 = Nodo (Value x) (iz) (de)
| head(index) == False && ((Nodo n iz de) == Vacio) = Nodo (Null) (setL (iz) (tail(index)) (x)) (de)
| head(index) == True && ((Nodo n iz de) == Vacio) = Nodo (Null) (iz) (setL (de) (tail(index)) (x))
| head(index) == False = Nodo (n) (setL (iz) (tail(index)) (x)) (de)
| head(index) == True = Nodo (n) (iz) (setL (de) (tail(index)) (x))
无法更改 Haskell 中的变量。这基本上就是 Haskell.
的全部要点
Of course there has to be a solution in the same ways lists are implemented in Haskell.
您也不能更改列表中的值。尝试一下。没办法。
let
创建新变量,但不能更改变量中的值。 let ... in ...
不会影响 ...
之外的任何内容!即使您为新变量赋予与另一个变量相同的名称 - 这意味着 ...
中的代码引用新变量,但 ...
之外的代码引用具有旧值的旧变量。
您的 set
函数的类型签名表明它以一棵树作为参数,并且 return 是一棵树。这是有原因的:它不必 return 作为其参数的同一棵树。您需要 return 一棵新树,但尽可能重复使用旧树的一些部分。每当你不想改变一个分支时,你可以在新树中使用旧树的分支。
Haskell 是纯函数式语言,简而言之,所有值都是不可变的,它们是值。考虑将名称绑定到值,x = 3 意味着 x 绑定到值 3,并且您无法更改该绑定。
因此,Haskell 中的功能是转换值。所以是的,在这种情况下,树被完全“复制”并返回修改,例如:
data Tree a = EmptyT | Node (Tree a) a (Tree a) deriving Show
replaceFirst x v EmptyT = EmptyT
replaceFirst x v (Node EmptyT tv EmptyT) = if (x == tv) then (Node EmptyT v EmptyT) else (Node EmptyT tv EmptyT)
replaceFirst x v (Node t1 tv EmptyT) = if (x == tv) then (Node t1 v EmptyT) else (replaceFirst x v t1)
replaceFirst x v (Node EmptyT tv t2) = if (x == tv) then (Node EmptyT v t2) else (replaceFirst x v t2)
replaceFirst x v (Node t1 tv t2) = if (x == tv) then (Node (replaceFirst x v t1) v (replaceFirst x v t2)) else (Node (replaceFirst x v t1) tv (replaceFirst x v t2))
请注意,您实际上是在创建一个新树,而不是用新值“替换”旧值。
试试看:
t1 = Node EmptyT 4 EmptyT
t2 = Node EmptyT 5 EmptyT
t3 = Node t1 7 t2
t4 = Node t3 5 t1
main = putStrLn (show(replaceFirst 4 8 t4))
我按照大学课程的说明实现了二叉树(注意:请注意通常的二叉树,它是一种不同的算法,但这并不重要)
在我的 set 函数 set :: Eq a => SparseArray a -> Int -> a -> SparseArray a
中,如果我使用它来更新节点的值,该函数将做的是复制一个值已更改的树,而不是像预期的那样更新值。
我认为这就像在 return 语句中使用 let ... in
符号一样简单,但程序需要能够更改任何变量。
当然必须有一个解决方案,与 Haskell 中实现列表的方式相同。
data Value a = Null | Value a
deriving (Eq,Read,Show)
data SparseArray a = Vacio | Nodo (Value a) (SparseArray a) (SparseArray a)
deriving (Eq,Read,Show)
set :: Eq a => SparseArray a -> Int -> a -> SparseArray a
set Vacio index x = Nodo (Value x) (Vacio) (Vacio)
set (Nodo n iz de) index x
| index < 0 = Nodo n iz de
| length(num2bin(index)) == 0 = Nodo (Value x) (iz) (de)
| head(num2bin(index)) == False && ((Nodo n iz de) == Vacio) = Nodo (Null) (setL (iz) (tail(num2bin(index))) (x)) (de)
| head(num2bin(index)) == True && ((Nodo n iz de) == Vacio) = Nodo (Null) (iz) (setL (de) (tail(num2bin(index))) (x))
| head(num2bin(index)) == False = Nodo (n) (setL (iz) (tail(num2bin(index))) (x)) (de)
| head(num2bin(index)) == True = Nodo (n) (iz) (setL (de) (tail(num2bin(index))) (x))
where setL :: Eq a => SparseArray a -> [Bool] -> a -> SparseArray a
setL Vacio index x = Nodo (Value x) (Vacio) (Vacio)
setL (Nodo n iz de) index x
| length(index) < 0 = Nodo n iz de
| length(index) == 0 = Nodo (Value x) (iz) (de)
| head(index) == False && ((Nodo n iz de) == Vacio) = Nodo (Null) (setL (iz) (tail(index)) (x)) (de)
| head(index) == True && ((Nodo n iz de) == Vacio) = Nodo (Null) (iz) (setL (de) (tail(index)) (x))
| head(index) == False = Nodo (n) (setL (iz) (tail(index)) (x)) (de)
| head(index) == True = Nodo (n) (iz) (setL (de) (tail(index)) (x))
无法更改 Haskell 中的变量。这基本上就是 Haskell.
的全部要点Of course there has to be a solution in the same ways lists are implemented in Haskell.
您也不能更改列表中的值。尝试一下。没办法。
let
创建新变量,但不能更改变量中的值。 let ... in ...
不会影响 ...
之外的任何内容!即使您为新变量赋予与另一个变量相同的名称 - 这意味着 ...
中的代码引用新变量,但 ...
之外的代码引用具有旧值的旧变量。
您的 set
函数的类型签名表明它以一棵树作为参数,并且 return 是一棵树。这是有原因的:它不必 return 作为其参数的同一棵树。您需要 return 一棵新树,但尽可能重复使用旧树的一些部分。每当你不想改变一个分支时,你可以在新树中使用旧树的分支。
Haskell 是纯函数式语言,简而言之,所有值都是不可变的,它们是值。考虑将名称绑定到值,x = 3 意味着 x 绑定到值 3,并且您无法更改该绑定。 因此,Haskell 中的功能是转换值。所以是的,在这种情况下,树被完全“复制”并返回修改,例如:
data Tree a = EmptyT | Node (Tree a) a (Tree a) deriving Show
replaceFirst x v EmptyT = EmptyT
replaceFirst x v (Node EmptyT tv EmptyT) = if (x == tv) then (Node EmptyT v EmptyT) else (Node EmptyT tv EmptyT)
replaceFirst x v (Node t1 tv EmptyT) = if (x == tv) then (Node t1 v EmptyT) else (replaceFirst x v t1)
replaceFirst x v (Node EmptyT tv t2) = if (x == tv) then (Node EmptyT v t2) else (replaceFirst x v t2)
replaceFirst x v (Node t1 tv t2) = if (x == tv) then (Node (replaceFirst x v t1) v (replaceFirst x v t2)) else (Node (replaceFirst x v t1) tv (replaceFirst x v t2))
请注意,您实际上是在创建一个新树,而不是用新值“替换”旧值。
试试看:
t1 = Node EmptyT 4 EmptyT
t2 = Node EmptyT 5 EmptyT
t3 = Node t1 7 t2
t4 = Node t3 5 t1
main = putStrLn (show(replaceFirst 4 8 t4))