在Haskell中表达一般计算的惯用方法

时间:2014-08-12 02:31:49

标签: haskell symbolic-computation

必须存在一种良好的惯用方式来表达类型级别的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

理想情况下,我希望保持开放性,因此this方法对我没有吸引力。我要求的太多了吗?

2 个答案:

答案 0 :(得分: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

请注意,我必须为Computation添加Double的实例,这只是consttest表达式应该等同于(((2^2) * 5) * 0.5) + 100,实际上比较这两个结果我会得到相同的值。

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

答案 1 :(得分: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*)

等。你可以称之为“计算组合器”。