为了提高我的 GHC 扩展知识,我决定尝试使用单位实现数字,并且我想要使用数字字面值来表示无单位的值。但由于 Haskell 所做出的开放世界假设,这似乎不是很实际。我无法让以下最简示例正常工作:
现在,如果我尝试执行类似于
不幸的是,由于Haskell的开放世界假设,即使数字具有单位,某些恶意人士也可能决定这些数字仍然是有效的
现在,开放世界假设并不是一个不合理的假设,特别是因为孤立实例并未被Haskell报告禁止。但在这种特定情况下,我真的想告诉GHC,对于
有没有办法明确陈述这一点?并且,有没有禁止孤立实例会让GHC在开放世界假设方面变得更加轻松呢?
当我尝试使用部分依赖类型使程序更加类型安全时,这种情况已经出现了几次。每当我想为基本情况指定
data Unit u a = Unit a
data NoUnit
instance Num a => Num (Unit NoUnit a) where
-- (+) (*) (-) abs signum not important
fromInteger = Unit . fromInteger
type family Multiply a b where
Multiply NoUnit NoUnit = NoUnit
multiply :: Num a => Unit u1 a -> Unit u2 a -> Unit (Multiply u1 u2) a
multiply (Unit a) (Unit b) = Unit $ a * b
现在,如果我尝试执行类似于
multiply 1 1
的操作,我希望结果值是明确的。因为获得Num (Unit u a)
类型的唯一方法是将u
设置为NoUnit
。剩下的a
应该由默认规则处理。不幸的是,由于Haskell的开放世界假设,即使数字具有单位,某些恶意人士也可能决定这些数字仍然是有效的
Num
实例,即使这种情况违反了(*) :: a -> a -> a
,因为带有单位的数字的乘法并不符合该类型签名。现在,开放世界假设并不是一个不合理的假设,特别是因为孤立实例并未被Haskell报告禁止。但在这种特定情况下,我真的想告诉GHC,对于
Unit
的Num
实例,唯一有效的幻影单位类型是NoUnit
。有没有办法明确陈述这一点?并且,有没有禁止孤立实例会让GHC在开放世界假设方面变得更加轻松呢?
当我尝试使用部分依赖类型使程序更加类型安全时,这种情况已经出现了几次。每当我想为基本情况指定
Num
、IsString
或IsList
实例,然后使用自定义值或函数来获取所有其他可能的情况时,这种情况就会出现。
Multiply
类型族应该有Multiply NoUnit y = y
和Multiply x NoUnit = x
,而不是Multiply NoUnit NoUnit = NoUnit
。此外,Adam Gundry得出结论,GHC内置的工具不足以支持良好的度量单位工作。你应该查看uom-plugin,这是一个支持此类功能的类型检查器插件。 - dfeuerDataKinds
。通过跟踪将每个值组合成7个基本SI单位中的每个单位的数量,似乎可以正确地处理所有SI单位。 - semicolon