Kyl*_*ush 3 haskell functional-programming pattern-matching
我在Haskell玩弄玩具项目.我正在实现一些我用其他语言构建的数据结构,以熟悉它们是如何在Haskell中构建的.这不是我的第一个函数式语言,我已经构建了几个项目,比如OCaml中的Scheme解释器,但我认为我的OCaml体验正在着色我是如何解决这个问题的.它不是非常重要,但可能对上下文有用,要知道我正在实现的数据结构是PR-Quadtree.
我想要做的是匹配和解构一个守卫内部的类型,一个与OCaml的匹配声明.
data Waypoint = WayPoint {
lat :: Float,
lon :: Float,
radius :: Float,
speed :: Float,
accel :: Float
} deriving (Show)
data Region = Region {
x :: Float,
y :: Float,
width :: Float
} deriving (Show)
data PRQuadtree = WhiteNode Region
| BlackNode Region Waypoint
| GreyNode {
topLeft :: PRQuadtree,
topRight :: PRQuadtree,
botLeft :: PRQuadtree,
botRight :: PRQuadtree,
region :: Region
} deriving (Show)
getRegion node
| BlackNode(r, _) = r
| WhiteNode(r) = r
| GreyNode = region node
Run Code Online (Sandbox Code Playgroud)
该getRegion功能是我有特别的问题之一.如果我想要做的事情不清楚:我想简单地提取参数的一个元素,但这取决于参数的代数数据类型的哪个成员.在OCaml我能做到:
let getRegion node = match node with
| BlackNode(r, _) = r
| WhiteNode(r) = r
| GreyNode = region(node)
Run Code Online (Sandbox Code Playgroud)
(或类似的东西,我的OCaml现在有点生疏).
然而,在Haskell中,这似乎不在r守卫分支的RHS范围内.我试图查找Pattern Guards,因为它们听起来像我想做的那样,但我真的不知道这里发生了什么.真的,我只是希望得到从LHS的LHS到等于RHS的绑定(取决于我们已经下降的后卫的哪个分支).
什么是惯用的Haskell做我想做的事情?
它可以实现如下:
getRegion :: PRQuadtree -> Region
getRegion (BlackNode r _) = r
getRegion (WhiteNode r) = r
getRegion GreyNode{region=r} = r
Run Code Online (Sandbox Code Playgroud)
甚至是
getRegion :: PRQuadtree -> Region
getRegion x = case x of
BlackNode r _ -> r
WhiteNode r -> r
GreyNode{} -> region x
Run Code Online (Sandbox Code Playgroud)
在Haskell中,预先设置类型签名是非常惯用的.
另一种选择是将region字段扩展到其他情况:
data PRQuadtree = WhiteNode { region :: Region }
| BlackNode { region :: Region , waypoint :: Waypoint }
| GreyNode {
topLeft :: PRQuadtree,
topRight :: PRQuadtree,
botLeft :: PRQuadtree,
botRight :: PRQuadtree,
region :: Region
} deriving (Show)
Run Code Online (Sandbox Code Playgroud)
现在,region将处理所有PRQuadtree价值观.
Haskell |在定义代数数据类型时使用ML,分隔不同的构造函数,但不使用它来分离case分支,而是使用语法
case .. of { pat1 -> e1 ; pat2 -> e2 ; ... }
Run Code Online (Sandbox Code Playgroud)
可以用缩进代替
case .. of
pat1 -> e1
pat2 -> e2
...
Run Code Online (Sandbox Code Playgroud)
另请注意,不鼓励使用部分字段选择器:
data A = A1 { foo :: Int } | A2
Run Code Online (Sandbox Code Playgroud)
在上面,foo A2键入检查但崩溃.另一方面,当所有构造函数中都存在字段时,我们不会面临这样的风险.