当前位置:  开发笔记 > 编程语言 > 正文

Haskell在卫兵中的类型解构

如何解决《Haskell在卫兵中的类型解构》经验,为你挑选了1个好方法。

我在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 

getRegion功能是我有特别的问题之一.如果我想要做的事情不清楚:我想简单地提取参数的一个元素,但这取决于参数的代数数据类型的哪个成员.在OCaml我能做到:

let getRegion node = match node with
    | BlackNode(r, _) = r
    | WhiteNode(r) = r
    | GreyNode = region(node)

(或类似的东西,我的OCaml现在有点生疏).

然而,在Haskell中,这似乎不在r守卫分支的RHS范围内.我试图查找Pattern Guards,因为它们听起来像我想做的那样,但我真的不知道这里发生了什么.真的,我只是希望得到从LHS的LHS到等于RHS的绑定(取决于我们已经下降的后卫的哪个分支).

什么是惯用的Haskell做我想做的事情?



1> chi..:

它可以实现如下:

getRegion :: PRQuadtree -> Region
getRegion (BlackNode r _) = r
getRegion (WhiteNode r) = r
getRegion GreyNode{region=r} = r

甚至是

getRegion :: PRQuadtree -> Region
getRegion x = case x of
  BlackNode r _ -> r
  WhiteNode r -> r
  GreyNode{} -> region x

在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)

现在,region将处理所有PRQuadtree价值观.

Haskell |在定义代数数据类型时使用ML,分隔不同的构造函数,但不使用它来分离case分支,而是使用语法

case .. of { pat1 -> e1 ; pat2 -> e2 ; ... }

可以用缩进代替

case .. of
   pat1 -> e1
   pat2 -> e2
   ...

另请注意,不鼓励使用部分字段选择器:

data A = A1 { foo :: Int } | A2

在上面,foo A2键入检查但崩溃.另一方面,当所有构造函数中都存在字段时,我们不会面临这样的风险.


也许你应该明确提到Haskell和ML在标记"case"的一般意义上都使用`|`,但是Haskell将它用于布尔警卫,而ML使用它(除其他外)用于模式匹配.还要提到的是,通常不鼓励使用非全场选择器(除了用于制作棱镜的非导出场选择器).
推荐阅读
惬听风吟jyy_802
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有