如何"延伸"一个(部分)记录选择器?

时间:2016-12-27 00:46:47

标签: haskell

NB:我在下面定义的类型只是用于此问题的一个方便示例;我确定没有必要让我在Haskell中推出自己的复数定义。

我不知道我是否在这里使用了正确的术语,但下面的选择器<section> <div class="contact-us-title"> <h1>Contact Us</h1> </div> <form class="contact-us-form" name="contactUsForm" ng-submit="vm.processContactForm()"> <div class="form-group"> <input placeholder="name" type="text" name="name" ng-model="vm.name" class="form-control" required /> <span class="label label-danger" ng-show="vm.submitted && contact-us-form.name.$error.required">Required!</span> </div> <div class="form-group"> <input placeholder="Email" type="email" name="email" ng-model="vm.email" class="form-control" required /> <span class="label label-danger" ng-show="vm.submitted && contact-us-form.email.$error.required">Required!</span> <span class="label label-danger" ng-show="vm.submitted && contact-us-form.$error.email">Invalid email!</span> </div> <div class="form-group"> <input name="headline" placeholder="Headline" type="text" ng-model="vm.headline" class="form-control" required/> <span class="label label-danger" ng-show="vm.submitted && contact-us-form.headline.$error.required">Required!</span> </div> <div class="form-group"> <textarea name="message" placeholder="Message" type="textbox" ng-model="vm.message" class="form-control" required></textarea> <span class="label label-danger" ng-show="vm.submitted && contact-us-form.subjectList.$error.required">Required!</span> </div> <input type="submit" id="submit-contact-form-btn"> </form> </section> 是我所说的部分&#34;记录选择器:

r

data Complex = Polar { r :: Float, y :: Float } | Rectangular { x :: Float, y :: Float } deriving Show 是&#34; partial&#34;因为它无法应用于所有 r值; e.g。

Complex

...但

r $ Polar 3 0
-- 3.0

然而,在这种情况下,r $ Rectangular 3 0 -- *** Exception: No match in record selector r 有一个合理的定义,即:

r $ Rectangular x y

GHCi拒绝-- assuming {-# LANGUAGE RecordWildCards #-} r :: Complex -> Float r Rectangular { .. } = sqrt $ (x * x) + (y * y) 的此定义,但出现r错误。

有没有办法扩展multiple declarations of ‘r’,以便它可以应用于任何 r值?

当然,我意识到我可以定义像

这样的东西
Complex

...但我想知道是否可以扩展现有的选择器-- assuming {-# LANGUAGE RecordWildCards #-} modulus :: Complex -> Float modulus Polar { .. } = r modulus Rectangular { .. } = sqrt $ (x * x) + (y * y)

1 个答案:

答案 0 :(得分:5)

不,首先应该永远不要引入IMO这样的唱片选择器。我把它写成

type ℝ = Float  -- Note that Double is usually more sensible

newtype S¹ = S¹ {ϑ :: ℝ}  -- in [-π, π[
newtype ℝPlus = ℝPlus {posℝ :: ℝ} -- in [0, ∞[

data Complex = Polar ℝPlus S¹
             | Rectangular ℝ ℝ
         deriving Show

这样,部分记录选择器的形式没有潜在的错误,也没有混淆解压缩等等。即使对于这样的“非记录类型”,你也可以编写自己的访问器,最好以镜头形式:

import Control.Lens

r :: Lens' Complex ℝPlus
r = lens get set
 where get (Polar r _) = r
       get (Rectangular x y) = ℝPlus . sqrt $ x^2 + y^2
       set (Polar _ θ) r = Polar r θ
       set (Rectangular x y) (ℝPlus r) = Rectangular (x * η) (y * η)
        where η = r / sqrt (x^2 + y^2)