haskell - 如何将 "extend"设为一个(部分)记录选择器?

标签 haskell

注意:我在下面定义的类型只是为了这个问题的目的而提供的一个方便的例子;我确信我没有必要在 Haskell 中推出我自己的复数定义。


我不知道我在这里使用的术语是否正确,但下面的选择器 r 是我所说的“部分”记录选择器的示例:

data Complex = Polar       { r :: Float, y :: Float }
             | Rectangular { x :: Float, y :: Float }
             deriving Show

r 是“部分”的,因为它不能应用于所有 Complex 值;例如

r $ Polar 3 0
-- 3.0

...但是

r $ Rectangular 3 0
-- *** Exception: No match in record selector r

然而,在这种情况下,r $ Rectangular x y 有一个合理的定义,即:

-- assuming {-# LANGUAGE RecordWildCards #-}
r :: Complex -> Float
r Rectangular { .. } = sqrt $ (x * x) + (y * y)

GHCi 拒绝 r 的定义,并出现 multiple declarations of ‘r’ 错误。

有没有办法扩展 r 以便它可以应用于任何 Complex 值?


当然,我意识到我可以定义类似的东西

-- assuming {-# LANGUAGE RecordWildCards #-}
modulus :: Complex -> Float
modulus Polar       { .. } = r
modulus Rectangular { .. } = sqrt $ (x * x) + (y * y)

...但我想知道是否可以扩展已经存在的选择器r

最佳答案

不,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)

关于haskell - 如何将 "extend"设为一个(部分)记录选择器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41337704/

相关文章:

haskell - Cabal 在需要分析库时不安装依赖项?

haskell - Aeson 中的单标签构造函数

logging - 如何登录 Haskell?

haskell - Haskell 中的模块、包和库有什么区别?

haskell - 在这个 haskell 示例中 loeb 如何终止?

haskell - 在 haskell 中使用 foldl 时不需要参数?

haskell - QuickCheck 实例在 cabal 包中属于哪里?

haskell - 为什么 Data.Traversable 中的 'for' 接受单子(monad) Action ?

haskell - State 和其他 MTL monad 的应用实例?

haskell - 数据结构中的自引用 - 检查相等性