3

必须存在一种良好的惯用方式来表达 Haskell 中类型级别的一般计算。我能想到的就是这个(非法的)OO 模仿。

class Computation where
  compute :: Computation -> Double -> Double

data Id = Id
instance Computation Id where 
  compute _ = id

data Square a = Computation a => Square a 
instance Computation (Square a) where 
  compute (Square underlying) x = sqr $ compute underlying x where square x = x*x

data Scale a = Computation a => Scale a Double
  compute (Scale underlying c) x = c * compute underlying x

理想情况下,我想保持开放,所以这种方法对我没有吸引力。我要求太多了吗?

4

2 回答 2

3

您当然可以使用您拥有的方法来做到这一点,您只需要正确获取语法和一些细节,但这肯定有效:

class Computation a where
    compute :: a -> Double

instance Computation Double where
    compute = id

data Square a = Square a

instance Computation a => Computation (Square a) where
    compute (Square underlying) = square $ compute underlying where square i = i * i

data Scale a = Scale a Double

instance Computation a => Computation (Scale a) where
    compute (Scale underlying c) = c * compute underlying

data Add a = Add a Double

instance Computation a => Computation (Add a) where
    compute (Add underlying c) = c + compute underlying

test :: Add (Scale (Scale (Square Double)))
test = Add (Scale (Scale (Square 2) 5) 0.5) 100

main :: IO ()
main = print $ compute test

请注意,我必须添加一个Computationfor的实例Double,这很简单const。该test表达式应该等效于(((2^2) * 5) * 0.5) + 100,实际上比较这两个结果我得到了相同的值。

不过,我不完全确定这是您想要的方法。这也并不等同于您发布的链接中显示的方法,使用这种编码表示变量将非常困难,因为没有好的方法可以输入所有变量值的映射以减少表达式。

于 2014-08-12T03:22:23.403 回答
0

这取决于你想用计算做什么,但一种惯用的方法是:

data Computation = Computation { compute :: Double -> Double }

然后你可以拥有:

idCmp :: Computation
idCmp = Computation id

squareCmp :: Computation
squareCmp = Computation (\i -> i * i)

composeCmp :: Computation -> Computation -> Computation
composeCmp b a = Computation (compute b . compute a)

scaleCmp :: Double -> Computation
scaleCmp r = Computation (r*)

等等。您可以称其为一种“计算组合器”。

于 2014-08-12T04:41:14.683 回答