我是哈斯凯尔的新手,我不时遇到一个问题,我将用几句话来描述.想象一下,我想为不同的度量声明不同的类型,因此Haskell类型系统会在我的公式中找到错误:
newtype Dist = Km Float
newtype Time = H Float
newtype Velocity = KmH Float
(/) :: Dist ? Time ? Velocity
(Km d) / (H t) = KmH (d / v)
(*) :: Velocity ? Time ? Dist
(KmH v) * (H t) = Km (v * t)
Run Code Online (Sandbox Code Playgroud)
所以,每当我尝试在我的公式中使用错误的度量单位时,编译器就会咬人.
问题是我不能像这样实现ad-hoc polimorphism.使用此代码,我带来了歧义 - 编译器可以区分我的运算符*和Prelude中定义的运算符.由于我需要不同类型的参数,因此也无法声明Num类的实例.
我想知道人们通常如何解决这个问题.
提前致谢!
如果你愿意,你可以隐藏通常的(*)
import Prelude hiding((*))
Run Code Online (Sandbox Code Playgroud)
或隐藏所有的Num
import Prelude hiding(Num(..))
Run Code Online (Sandbox Code Playgroud)
然后你可以定义你自己的乘法,可能是沿着这条线
class Mul a b c | a b -> c, b c -> a, c a -> b where
(*) :: a -> b -> c
Run Code Online (Sandbox Code Playgroud)
您可以尝试重新配置您的单位系统.尝试这样的事情:
data Unit = Unit String
| Unit :/: Unit
| Unit :*: Unit
| Unit :^: Int
deriving (Show,Eq)
instance Num Unit where
-- Insert reasonable definition here
x * y = ...
data UnitNum n = UN n Unit
instance Num (Num n) => UnitNum n where
UN n u + Un k u' | u == u' = UN (n+k) u
| otherwise = error ...
-- insert other definitions here.
km,h,kmh :: Unit
km = Unit "km"
h = Unit "h"
kmh = km / h
Run Code Online (Sandbox Code Playgroud)
类似的东西,但在维度包中实现了完全不同.阅读源代码,它是有文化的Haskell,非常好理解.对于大多数科学应用,此代码应该足够好.