【发布时间】:2014-10-15 10:31:27
【问题描述】:
我正在尝试以幻象类型乘以单元数组(来自dimensional),但我遇到了函数依赖问题。问题的简化版本如下:
我有以下类型
data F (a:: [*]) = F String
其中字符串表示外语表达式和表示类型列表的幻像类型。
我可以做类似的事情
x = F "x" :: F '[Double]
y = F "(1,3)" :: F '[Int, Int]
我设法通过创建一个Nums 类来实现这样的算术运算符,该类是Num 的列表。
class Nums (a::[*])
instance Nums '[]
instance (Num a, Nums as) => Num (a ': as)
那我可以实例化Num F
instance Nums as => F as where
(F a) * (F b) = F (a ++ "*" ++ b)
... etc ...
现在,我正在尝试使用物理单位来做同样的事情。我可以通过这种方式使用一种类型的列表来做到这一点
import qualified Numeric.Units.Dimensional as Dim
data F (a::[*]) = F String
(!*!) :: (Num n, Dim.Mul a b c) => F '[Dim.Dimensional v a n]
-> F '[Dim.Dimensional v b n]
-> F '[Dim.Dimensional v c n]
(F a) !*! (F b) = F (a ++ "*" ++ b)
这似乎可行,我可以“乘”2个不同单位的'F',结果是正确的单位。
显然,我想将其推广到任何列表,并使用与 Nums 相同的技巧,我称之为 Muls。
class Muls a b c | a b -> c
instance '[] '[] '[]
instance (Num n, Mul a b c, Muls as bs cs)
=> Muls (Dim.Dimensional v a n ': as)
(Dim.Dimensional v b n ': bs)
(Dim.Dimensional v c n ': cs)
!*! :: (Muls as bs cs) => F as -> F bs -> F cs
(F a) !*! (F b) = F (a ++ "*" ++ b)
我收到Illegal Instance declaration 错误:
Illegal instance declaration for
‘Muls
(Dim.Dimensional v a n : as)
(Dim.Dimensional v b n : bs)
(Dim.Dimensional v c n : cs)’
The coverage condition fails in class ‘Muls’
for functional dependency: ‘a b -> c’
Reason: lhs types ‘Dim.Dimensional v a n : as’, ‘Dim.Dimensional
v b n
: bs’
do not jointly determine rhs type ‘Dim.Dimensional v c n : cs’
Using UndecidableInstances might help
In the instance declaration for
‘Muls (Dim.Dimensional v a n : as) (Dim.Dimensional v b n
: bs) (Dim.Dimensional v c n : cs)’
如果我使用UndecidableInstances 扩展名,它似乎确实有效。我的问题是,为什么我需要这个扩展,有没有办法避免它?
或者,我可能可以使用dimensional 的类型系列版本来完成这项工作。不幸的是,我需要自定义单位,不清楚dimensional-tf 是否支持用户定义的单位。
【问题讨论】:
标签: haskell ghc functional-dependencies