

Making ad-hoc polymorphism less ad hoc - Swizec
http://swizec.com/blog/week-20-making-ad-hoc-polymorphism-less-ad-hoc/swizec/6564

======
thinkpad20
Very well-written, and interesting. I learned a lot about how haskell type
classes are implemented through this paper:
[http://web.cecs.pdx.edu/~mpj/pubs/pldi93.html](http://web.cecs.pdx.edu/~mpj/pubs/pldi93.html)

I've been working on a language which attempts to put type classes into a
dynamic language. The implementation is a little interesting, because as I've
tinkered with it, I've discovered essentially two cases of overloaded
functions:

* Ones where you can choose which implementation to use based on _argument type_. Similar to interfaces in Java, Go, etc, and multiple-dispatch languages. Also (I think) Rust only allows traits of this kind, but that might not be correct.

* Ones where you choose the implementation based on the _return type_. This is mostly (from what I can tell) unique to Haskell and similar languages. It's what lets you write `return :: a -> m a` and be able to write `foo = return 3` and have `foo` work in any monad.

Both of these approaches have their advantages and use cases. Haskell's system
is nice because it allows for both, but because of how things are implemented,
there's no introspection, so for example, a list "objects that implement Show"
isn't feasible, because there's no way to inspect an object at runtime to
determine its type. Or this is my understanding anyway.

In my language, I treat each case differently, and can generate appropriate
generic functions by inferring from the declared type signature(s) in the type
class which case they fall into. Subsequently, its possible to mimic both
behaviors in a dynamic setting. The only limitation (which I might be able to
avoid) is that using the second type requires an explicit cast; as in you can
say `foo = pure 2; bar = foo : [Num]; baz = foo : Just Num`. Of course,
introspection has a performance penalty as well.

Just thought some might find this interesting :)

~~~
swift
If you're at the point where you think it's ready, you should consider posting
your language to HN. Seems like it might interest people here.

One note: it is indeed possible to create a list of "objects that implement
Show" in Haskell, but it's a bit clunky. Look into existential types.

~~~
thinkpad20
It's not ready yet (among other things, it's currently type checked using
Hindley-Milner, and I think I want to transition it to gradual typing), but
it's getting there. I am hoping to post it to HN and get some feedback. I have
a few other projects in the works, though, which might be in a finished form
first...

Existential types are kind of the same, but they require the declaration of
extra types to use them (for example, the `Obj` type used in the example on
the Haskell wiki entry on existential types), which is clunky as you say. But
at first glance, they do seem to provide a similar degree of power.

------
Iceland_jack
The paper is quite old, Num is no longer a subclass of Eq:

    
    
        ghci> :i Num
        class Num a where
          (+) :: a -> a -> a
    

thus ‘memsq’ would look as follows:

    
    
        memsq :: (Eq a, Num a) => [a] -> a -> Bool
        memsq xs x = square x `elem` xs

------
nwhitehead
Cool! I've used type classes in Haskell but had no idea how you could even
start to implement them. It's like learning about vtable pointers for a C++
programmer.

------
ScottBurson
Thanks -- this is very helpful!

(Wonder why I despise Markdown? Take a look at the paragraph immediately under
the heading "Type Classes". I suppose this could be a formatting error, but
I'm betting it's a Markdown misinterpretation.)

~~~
Swizec
Yep you're right, that's a markdown misinterpretation. But I really like
markdown, it's so much easier to use than most other such things.

~~~
loup-vaillant
One day, I'm going to reimplement Markdown, and call that _Rightdown_.

No more misinterpretation, and no more uncaught syntax error.

------
gus_massa
Small format correction: The article says &gt; instead of > . For example:

    
    
      square   :: Num a =&gt; a -&gt; a
    
      square   :: Num a => a -> a

~~~
Swizec
Thanks, fixed.

~~~
gus_massa
Another similar problem with &amp; in:

    
    
      instance Eq a, Eq b => Eq (a,b) where
       (u,v) == (x,y)     = (u == x) &amp; (v == y)
    

(I'd check &lt; in spite there are no examples in the article.)

