我想定义一个数据类型Polar
来使用极坐标执行计算:
data Polar = Polar { distance :: Double, angle :: Double }
并具有rotate
,sum
等功能。
然后,我希望有一个"同义词类" (或只是别名)喜欢
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}
答案 0 :(得分:4)
类型别名通常使用 type
关键字构建。例如:
type TwsTwa = Polar
现在,您可以在代码中的任何位置使用TwsTwa
,编译器会将其转换为幕后的Polar
。
但是现在我们当然还没有定义tws :: TwsTwa -> Double
和twa :: 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
但是,嘿,它保护你不会意外地传入错误的类型,而类型的同义词只是为了方便。