如果你无法在 Haskell 中更改变量的值,那么如何创建数据结构呢?

发布于 2024-08-12 08:33:25 字数 479 浏览 6 评论 0原文

正如标题所示。

我有以下创建二叉搜索树的代码,但如果我希望它根据用户输入动态创建和更改,如果我无法更改 haskell 中变量的值,我该怎么做?!?

find :: (Ord a) => Node a -> a -> Bool
find (Node val left right) s
    | s == val      = True
    | s < val       = find left s
    | s > val       = find right s

find Empty s = False

data Node a = Node a (Node a) (Node a)
              | Empty

myTree = Node "m"   (Node "a" Empty Empty)
                    (Node "z" Empty Empty)

提前致谢!

As per the title.

I have the following code which creates a binary search tree, but if I want it created and changed dynamically with user input, how would I do that if I can't change the value of a variable in haskell?!?

find :: (Ord a) => Node a -> a -> Bool
find (Node val left right) s
    | s == val      = True
    | s < val       = find left s
    | s > val       = find right s

find Empty s = False

data Node a = Node a (Node a) (Node a)
              | Empty

myTree = Node "m"   (Node "a" Empty Empty)
                    (Node "z" Empty Empty)

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

め七分饶幸 2024-08-19 08:33:25

纯函数数据结构背后的想法是计算新值而不是更改它们,并在参数中(递归地)传递它们而不是全局存储它们。

因此,给定一个函数,

insert :: Ord a => Node a -> a -> Node a

您的程序可能如下所示

-- Let the user enter k values that are stored in a tree structure
addTreeItems :: Int -> Node Int -> IO (Node Int)
addTreeItems 0 tree = return tree
addTreeItems k tree = do
    putStr "Enter new item: "
    item <- readLn
    addTreeItems (k - 1) (insert tree item) -- Recursively pass the tree

main = do
    tree <- addTreeItems 10 Empty
    -- ...

使用单子辅助函数,这可以简化为类似的内容

(foldl insert Empty) `liftM` (sequence $ replicate k (putStr "Enter new item: " >> readLn))

如果您想更新某个位置的值,您将需要更高级的数据结构,例如 拉链,但仍然是纯功能性的!

The idea behind purely functional data structures is to compute new values instead of changing them and to pass them (recursively) in parameters instead of storing them globally.

So given a function

insert :: Ord a => Node a -> a -> Node a

your programm could look like this

-- Let the user enter k values that are stored in a tree structure
addTreeItems :: Int -> Node Int -> IO (Node Int)
addTreeItems 0 tree = return tree
addTreeItems k tree = do
    putStr "Enter new item: "
    item <- readLn
    addTreeItems (k - 1) (insert tree item) -- Recursively pass the tree

main = do
    tree <- addTreeItems 10 Empty
    -- ...

Using monadic helper functions, this could be simplified to things like

(foldl insert Empty) `liftM` (sequence $ replicate k (putStr "Enter new item: " >> readLn))

If you want to update values at a certain position, you'll need more advanced datastructures like a zipper, that are nevertheless still purely functional!

乖乖公主 2024-08-19 08:33:25

Dario gave a good direct answer. If you want more in-depth information, there's Purely Functional Data Structures by Chris Okasaki, an entire book on the subject. I bought it myself, but sadly, I don't have the time to experiment with the ideas.

无畏 2024-08-19 08:33:25

您分配一个新的树节点,而旧的保留下来。这项技术需要一个非常好的分配器,但它支持各种漂亮的设备,因为程序的其他部分仍然可以访问旧节点。对于某些类型的推测算法或涉及所谓“持久数据结构”的其他技巧来说,这是天赐之物。

最终你为你的树分配了一个新的根,然后呢?正如达里奥所说,您将它作为参数传递给函数(而不是将其存储在全局变量中)。

因此,

  • 在堆上分配的结构体中的字段的突变会成为在堆上分配新结构体。

    在堆上

  • 全局变量的变异变成了将参数传递给函数

有时,将 C 中的全局变量集合和将它们全部放在堆上分配的对象中。


PS 如果你真的愿意,你可以在 Haskell 中拥有可变的全局变量。毕竟,它是世界上最好的命令式编程语言(根据 Wadler 或 Peyton Jones 的说法,我忘记了是谁)。但如果你问这个问题,那你真的不想问。然而。

You allocate a new tree node and the old one sticks around. This technique requires a really good allocator, but it enables all sorts of nifty devices because other parts of the program still have access to old nodes. This is a godsend for certain kinds of speculative algorithms or other tricks involving so-called "persistent data structures".

Eventually you allocate a new root for your tree and what then? As Dario says, you pass it as a parameter to a function (instead of storing it in a global variable).

So

  • Mutation of a field in a struct allocated on the heap becomes allocation of a new struct on the heap.

  • Mutation of a global variable becomes passing a parameter to a function

Sometimes it also makes sense to take what would have been a collection of global variables in C and put them all in an object allocated on heap.


P.S. If you really want to, you can have mutable global variables in Haskell. It is, after all, the world's finest imperative programming language (according to Wadler or Peyton Jones, I forget whom). But if you are asking this question, you really don't want to. Yet.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文