gpt4 book ai didi

Haskell 重用模式

转载 作者:行者123 更新时间:2023-12-04 04:25:14 24 4
gpt4 key购买 nike

在下面的代码中,相同的模式匹配 (节点 n 左右)由三个不同的函数使用。如果我想添加一个模式,例如 (节点n(叶)(叶))或更改我的数据类型,我必须更改所有功能。有没有办法重用这些模式,所以我只需要定义一次?

data Tree = Node Int Tree Tree
| Leaf

add :: Tree -> Int -> Tree
add (Node n left right) x = Node (n+x) (add left x) (add right x)
add (Leaf) x = Leaf

subtract :: Tree -> Int -> Tree
subtract (Node n left right) x = Node (n-x) (subtract left x) (subtract right x)
subtract (Leaf) x = Leaf

swap :: Tree -> Tree
swap (Node n left right) = Node n right left
swap (Leaf) = Leaf

我试过了
matchNode = (PNode n left right)
add matchNode x = Node (n+x) (add left x) (add right x)

但它不允许我使用模式_,我无法提取 n , 离开 , 和 从中。

最佳答案

这仅回答了部分:

If I want to [...] change my datatype, I have to change all the functions.



在这种情况下,您可以避免更改所有功能
使用 pattern synonyms extension 定义自定义模式:
{-# LANGUAGE PatternSynonyms #-}

-- The old type:
-- data Tree = Node Int Tree Tree
-- | Leaf

-- The new type
data Tree = NewNode Tree Int Tree -- changed name & argument order
| Leaf

pattern Node n left right = NewNode left n right

add :: Tree -> Int -> Tree
add (Node n left right) x = Node (n+x) (add left x) (add right x)
add (Leaf) x = Leaf

-- etc.

上面,我重命名了旧的构造函数 Node进入 NewNode ,也改变了它的论点的顺序。然后,我定义了一个 pattern Node作为兼容性桥梁,使下面的旧模式再次起作用。

问题还问:

Is there a way to reuse these patterns, so I only have to define them once?



@PyRulez 评论了使用记录通配符来缩短模式。这是一种可能的方法:
{-# LANGUAGE ViewPatterns, RecordWildCards #-}

-- an auxiliary record type to define the custom pattern
data R = RNode { left::Tree , n::Int, right::Tree } | RLeaf
-- a function to convert a Tree to a R
toR :: Tree -> R
toR (NewNode l n r) = RNode l n r
toR _ = RLeaf

-- Here we use a shorter pattern:
add2 :: Tree -> Int -> Tree
add2 (toR -> RNode{..}) x = Node (n+x) (add2 left x) (add2 right x)
-- ^^^^^^^^^^^^^^^^^^^ this brings in scope left, n, right
add2 (toR -> RLeaf) x = Leaf

在这种特定情况下,空间并没有很大的 yield 。然而,无论模式有多大,在记录定义(和辅助函数)之后我们只需要写 toR -> RNode{...} .

不过,我不确定我是否真的喜欢这个。

首先,该记录用三个(部分!)函数污染了全局 namespace left :: R -> Tree, n :: R -> Int, right :: R -> Tree .如果您尝试使用例如,这将触发一些警告。 n作为另一个不相关函数 ( The local name shadows the global name n) 的参数。

其次,记录通配符扩展将一些未写在代码中的变量引入范围——读者必须知道(或猜测)这些变量是什么。另请注意 RNode{..}模式带来例如 n进入与全局名称不同类型的作用域: Int而不是 R -> Int .读者可能会认为 n是全局的,即使在类型级别也会被误导。

第三,上面的代码使用了 View 模式,目前这些模式让穷举检查器感到困惑:
Patterns.hs:23:1: Warning:
Pattern match(es) are non-exhaustive
In an equation for ‘add2’: Patterns not matched: _ _

在这种特定情况下,我们可以简单地写
add2 :: Tree -> Int -> Tree
add2 (node -> RNode{..}) x = Node (n+x) (add2 left x) (add2 right x)
add2 _ x = Leaf

以避免警告,但一般来说,我们并不总是有这种选择。

关于Haskell 重用模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31214814/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com