Haskell中类型的订单层次结构

时间:2020-10-21 00:03:05

标签: haskell types

我正在尝试双向转换类型

是否可以像枚举中那样根据类型创建订单层次结构?

data Longitud a = Pies Float | Pulgadas Float | Yardas Float | Cm Float | Metros Float deriving (Show)

--toYardas:: Longitud a -> Longitud a
toYardas (Pies x) = Yardas $ x/3
toYardas x = toYardas $ toPies x

toPies (Pulgadas x) = Pies $ x/12
toPies (Yardas x) = Pies $ x*3
toPies x = toPies $ toYardas x --if bigger type
toPies x = toPies $ toPulgadas x --if smaller type

toPulgadas (Cm x) = Pulgadas $ x/2.54
toPulgadas (Pies x) = Pulgadas $ x*12

toCm (Pulgadas x) = Cm $ x*2.54
toCm (Metros x) = Cm $ x*100

toMetros (Cm x) = Metros $ x/100

编辑:我正在寻找一种比较Cm> Metros或Cm

2 个答案:

答案 0 :(得分:2)

由于您想将单位本身称为一等值,而不仅仅是保存数字的构造函数,并且由于要统一存储它们,因此我建议重构类型以将单位和值保存在两个单独的字段中:

data Unit = Pies | Pulgada | ... deriving Ord

data Longitud = Longitud Unit Float

然后,由于它们与值分开,因此您可以轻松比较单位:

toPies old@(Longitud unit amt) = case unit of
  Pies -> old
  Pulgadas -> Longitud Pies $ amt / 12
  Yardas -> Longitud Pies $ amt * 3
  u | u > Yardas -> toPies $ toYardas old
    | u < Pulgadas -> toPies $ toPulgadas old
    | otherwise = error "unknown unit"

我确实同意Louis的观点,即只要将Ord实例添加到您的类型上,它就可以在这种情况下正常工作。但是,当您真正关心的只是两个纵向值,而从未期望将它们的大小进行比较时,比较两个Longitud值对我来说真的不合适。

答案 1 :(得分:0)

deriving (Ord)实际上应该准确地完成您想要的事情,包括类型构造函数。来自here

由Eq和Ord的派生实例自动引入的类方法是(==),(/ =),compare,(<),(<=),(>),(> =),max和min 。定义了后七个运算符,以便按字典顺序比较其参数与给定的构造函数集,而数据类型声明中的较早构造函数的计数要小于后来的构造函数。