Search code examples
haskelltype-variables

Ambiguous type variable 'blah' in the constraint... how to fix?


I'm trying to write a simple ray-tracer in Haskell. I wanted to define a typeclass representing the various kinds of surfaces available, with a function to determine where a ray intersects them:

{-# LANGUAGE RankNTypes #-}

data Vector = Vector Double Double Double
data Ray = Ray Vector Vector

class Surface s where
  intersections :: s -> Ray -> [Vector]

-- Obviously there would be some concrete surface implementations here...

data Renderable = Renderable
  { surface    :: (Surface s) => s
  , otherStuff :: Int
  }

getRenderableIntersections :: Renderable -> Ray -> [Vector]
getRenderableIntersections re ra = intersections (surface re) ra

However this gives me the error:

Ambiguous type variable 's' in the constraint:
  'Surface'
    arising from a use of 'surface'

(The actual code is more complex but I've tried to distill it to something simpler, while keeping the gist of what I'm trying to achieve).

How do I fix this? Or alternatively, given that I come from a standard OO background, what am I fundamentally doing wrong?


Solution

  • Please don't use existential types for this! You could, but there would be no point.

    From a functional standpoint you can drop this typeclass notion of Surface entirely. A Surface is something that maps a Ray to a list of Vectors, no? So:

    type Surface = Ray -> [Vector]
    
    data Renderable = Renderable
     { surface    :: Surface
     , otherStuff :: Int
    }
    

    Now if you really want, you can have a ToSurface typeclass essentially as you gave:

    class ToSurface a where
         toSurface :: a -> Surface
    

    But that's just for convenience and ad-hoc polymorphism. Nothing in your model requires it.

    In general, there are a very few use cases for existentials, but at least 90% of the time you can substitute an existential with the functions it represents and obtain something cleaner and easier to reason about.

    Also, even though it may be a tad too much for you to take in, and the issues don't exactly match, you might find useful some of Conal's writing on denotational design: http://conal.net/blog/posts/thoughts-on-semantics-for-3d-graphics/