Search code examples
haskellsymbolic-computation

Idiomatic way to express general computations in Haskell


There must exist a good idiomatic way to express general computations in Haskell on type level. All I can come up with is this (illegal) OO imitation.

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

Ideally, I would like to retain openness, so this approach doesn't appeal to me. Am I asking for too much?


Solution

  • You can certainly do it with the approach you have, you just need to get the syntax and some of the details right, but this certainly works:

    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
    

    Note that I had to add an instance of Computation for Double, which is just simply const. The test expression should be equivalent to (((2^2) * 5) * 0.5) + 100, and indeed comparing these two results I get the same value.

    I'm not entirely sure this is the approach that you wanted, though. This also isn't really equivalent to the method shown in the link you posted, expressing variables would be pretty difficult with this encoding as there's no good way to feed in a map of all variable values to reduce the expression.