数据类型的别名

时间:2018-06-09 19:08:30

标签: haskell

我想定义一个数据类型Polar来使用极坐标执行计算:

data Polar = Polar { distance :: Double, angle :: Double }

并具有rotatesum等功能。

然后,我希望有一个"同义词类" (或只是别名)喜欢 TwsTwa(真风速和真风角)如

data TwsTwa = TwsTwa { tws :: Double, twa :: Double }

无需重新定义功能。

以下是使用班级的最佳解决方案吗? 它是较短的吗?请注意我指的是TwsTwa的定义方式,而不是写Polar的通用代码有多困难。 还有什么替代方案?

-- .................................................
-- .................................................
class PolarFamily tPolar where
  distanceP :: tPolar -> Double
  angleP :: tPolar -> Double
  toMe :: Polar -> tPolar

  rotate :: tPolar -> Double -> tPolar
  rotate pol ang =
     toMe $ Polar {distance=distanceP pol, angle=(angleP pol) + ang}

  sumP :: tPolar -> tPolar -> tPolar
  sumP p1 p2 =
     toMe $ Polar {distance=(distanceP p1)+(distanceP p2), 
            angle=(angleP p1)+(angleP p2) } -- caution: wrong calculation

-- .................................................
-- .................................................
data Polar = Polar { distance :: Double, angle :: Double }

instance PolarFamily Polar where
  distanceP = distance
  angleP = angle
  toMe p = p

TwsTwa的定义如下:

-- .................................................
-- .................................................
data TwsTwa = TwsTwa { tws :: Double, twa :: Double }

instance PolarFamily TwsTwa where
  distanceP = tws
  angleP = twa
  toMe Polar{ distance=d, angle=a} = TwsTwa {tws=d, twa=a}

2 个答案:

答案 0 :(得分:4)

类型别名通常使用 type关键字构建。例如:

type TwsTwa = Polar

现在,您可以在代码中的任何位置使用TwsTwa,编译器会将其转换为幕后的Polar

但是现在我们当然还没有定义tws :: TwsTwa -> Doubletwa :: TwsTwa -> Double,我们可以这样做:

tws :: TwsTwa -> Double
tws = distance

twa :: TwsTwa -> Double
twa = angle

我们可能也希望声明一个双向模式同义词,这样我们就可以使用TwsTwa“数据构造函数”(虽然从技术上讲,我们只定义了同义词,而不是新词):

{-# LANGUAGE PatternSynonyms #-}

pattern TwsTwa :: Double -> Double -> Polar
pattern TwsTwa { tws, twa } = Polar twa tws
-- can use record syntax
-- including field accesses, record updates, and record construction

虽然我个人认为定义新的构造函数和模式有点矫枉过正。只需使用类型同义词即可。

使用类型同义词有以下几个原因:

  • 降低某种类型的复杂性。例如:

    type MightError a = Either String a
    type TwoList a = ([a], [a])
    
  • 使用稍后可以更改的类型,例如:

    type Time = Int
    

    如果我们稍后改变主意,我们可以将Time设置为Integer,然后自动更新Time的所有功能。

答案 1 :(得分:2)

这就是我的意思,不是最好的,而是一个有趣的选择

import Control.Lens

newtype Polar = Polar { unPolar :: (Double,Double) } deriving Show
newtype TwsTwa = TwsTwa { unTws :: (Double,Double) } deriving Show

class ToTup a where
  -- You could make them accept any type instead of just Double but idk
  iTup :: Iso' (Double,Double) a
  unPol :: a -> (Double,Double)

  rotate :: Double -> a -> a
  rotate ang = under iTup (\(x,y) -> (y,x+ang)) 

  sumP :: a -> a -> a
  sumP p1 = under iTup (\(x,y) -> unPol p1 & (\(x1,y1) -> (x1+x,y1+y))) 

instance ToTup Polar where
  iTup = iso Polar unPolar 
  unPol = unPolar

instance ToTup TwsTwa where
  iTup = iso TwsTwa unTws
  unPol = unTws

但是,嘿,它保护你不会意外地传入错误的类型,而类型的同义词只是为了方便。