这是一种表示现实世界物理单位的数据类型:
import qualified Prelude as P
import Prelude hiding ((+), (*), (/), (-), Int, pi)
data Int = Zero | Succ Int | Pred Int
data Unit :: Int -> Int -> Int -> * where
U :: Double -> Unit m s kg
(+) :: Unit m s kg -> Unit m s kg -> Unit m s kg
(-) :: Unit m s kg -> Unit m s kg -> Unit m s kg
(*) :: Unit m1 s1 kg1 -> Unit m2 s2 kg2 -> Unit (Plus m1 m2) (Plus s1 s2) (Plus kg1 kg2)
(/) :: Unit m1 s1 kg1 -> Unit m2 s2 kg2 -> Unit (Minus m1 m2) (Minus s1 s2) (Minus kg1 kg2)
和Show实例:
instance Show (Unit m s kg) where
show (U a) = show a
通过这种方式,我只能显示值而不是类型(是时间,速度还是长度类型)。我想知道如何获得类型参数m,s,kg然后显示它?
完整代码为here。
答案 0 :(得分:5)
您还需要更多扩展程序:
{-# LANGUAGE PolyKinds, ScopedTypeVariables #-}
PolyKinds
打开更多邪恶类hackery,ScopedTypeVariables
允许您在函数定义中引用实例头中绑定的类型变量并键入签名。
然后我们可以写下以下内容:
data Proxy a = Proxy
class IntRep (n :: Int) where
natToInt :: Proxy (n :: Int) -> Integer
instance IntRep Zero where
natToInt _ = 0
instance (IntRep n) => IntRep (Succ n) where
natToInt _ = 1 P.+ (natToInt (Proxy :: Proxy n))
instance (IntRep n) => IntRep (Pred n) where
natToInt _ = (natToInt (Proxy :: Proxy n)) P.- 1
Proxy
与PolyKinds
相结合,可以引用n
的实例声明中定义的IntRep
。计算幻像类型的通常策略是使用undefined :: t
,但undefined
有*
种,因此undefined :: Zero
是一种不匹配。由于您将Unit
定义为Unit :: Int -> Int -> Int -> *
而非Unit :: * -> * -> * -> *
,因此需要额外的误导。
最后是Show
实例:
instance (IntRep m, IntRep s, IntRep kg) => Show (Unit m s kg) where
show (U a) = unwords [show a, "m^" ++ u0, "s^" ++ u1, "kg^" ++ u2]
where u0 = show $ natToInt (Proxy :: Proxy m)
u1 = show $ natToInt (Proxy :: Proxy s)
u2 = show $ natToInt (Proxy :: Proxy kg)
和
Prelude> main
0.1 m^1 s^-1 kg^0
补充阅读:http://comments.gmane.org/gmane.comp.lang.haskell.glasgow.user/22159