我正在尝试乘以单位数组(来自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
error :
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
支持用户定义的单位。