语境
我正在编写一个代表 SI 前缀的 Haskell 模块:
module Unit.SI.Prefix where
每个 SI 前缀都有对应的数据类型:
data Kilo = Kilo deriving Show
data Mega = Mega deriving Show
data Giga = Giga deriving Show
data Tera = Tera deriving Show
-- remaining prefixes omitted for brevity
问题
我想写一个函数,当应用两个 SI 前缀时,静态确定两个前缀中的哪个更小。例如:
-- should compile:
test1 = let Kilo = smaller Kilo Giga in ()
test2 = let Kilo = smaller Giga Kilo in ()
-- should fail to compile:
test3 = let Giga = smaller Kilo Giga in ()
test4 = let Giga = smaller Giga Kilo in ()
初步解决方案
这是一个使用类型类和功能依赖项的解决方案:
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
class Smaller a b c | a b -> c where smaller :: a -> b -> c
instance Smaller Kilo Kilo Kilo where smaller Kilo Kilo = Kilo
instance Smaller Kilo Mega Kilo where smaller Kilo Mega = Kilo
instance Smaller Kilo Giga Kilo where smaller Kilo Giga = Kilo
instance Smaller Kilo Tera Kilo where smaller Kilo Tera = Kilo
instance Smaller Mega Kilo Kilo where smaller Mega Kilo = Kilo
instance Smaller Mega Mega Mega where smaller Mega Mega = Mega
instance Smaller Mega Giga Mega where smaller Mega Giga = Mega
instance Smaller Mega Tera Mega where smaller Mega Tera = Mega
instance Smaller Giga Kilo Kilo where smaller Giga Kilo = Kilo
instance Smaller Giga Mega Mega where smaller Giga Mega = Mega
instance Smaller Giga Giga Giga where smaller Giga Giga = Giga
instance Smaller Giga Tera Giga where smaller Giga Tera = Giga
instance Smaller Tera Kilo Kilo where smaller Tera Kilo = Kilo
instance Smaller Tera Mega Mega where smaller Tera Mega = Mega
instance Smaller Tera Giga Giga where smaller Tera Giga = Giga
instance Smaller Tera Tera Tera where smaller Tera Tera = Tera
上面的解决方案似乎正确地解决了这个问题,但是它有一个缺点:类型类实例的数量是类型数量的二次方。
问题
有没有办法将类型类实例的数量减少到与类型数量成线性关系,也许是通过利用对称性?
在这里使用 Template Haskell 可能更合适,在这种情况下,请随意提出建议作为解决方案。
谢谢!