I have to admit that I have only basic knowledge of Python and currently learning Haskell.
I was wondering if the concept of type classes exist/makes sense in Python or in Clojure (or some other dynamically-strongly typed language) ?
In other words, if I have a function name f
then depending on the run time parameter fed to f
a different function implementation will be invoked (like the ==
function for types that belong to the Eq
type class in Haskell). Does such a concept exist in dynamic languages such as Clojure/Python ?
Multimethods seem to do the trick in Clojure. For example, let's define a plus
function that adds numbers but concatenates the string representation of anything else.
(defmulti plus (fn [& xs] (every? number? xs)))
(defmethod plus true [& xs] (apply + xs))
(defmethod plus false [& xs] (apply str xs))
(plus 1 8) ;9
(plus 1 \8) ;"18"
Multimethods are functions ((ifn? plus)
is true
), so are as first-class as you could wish:
(let [z (partial plus 5)] (z \3)) ;"53"
You can get pretty close to this with multimethods or protocols in clojure, or with simple member functions (class methods) in python. There's one important feature missing in each of these that's present in haskell, though: return-type polymorphism.
The compiler knows what type you "expect" a function to return, and can dispatch to a different implementation accordingly. This means that the same function, called on the same arguments, can do something entirely different, depending on what's done with its return value. For example:
Prelude> read "[5,6,7]" :: [Int]
[5,6,7]
Prelude> read "[5,6,7]" :: [Double]
[5.0,6.0,7.0]
Likewise, you can even have polymorphic constants, which have a different value for each typeclass instance:
Prelude Data.Word> (minBound, minBound, minBound) :: (Int, Bool, Word8)
(-9223372036854775808,False,0)
You can't really do this in a dynamic language because there's no type inference. You can fake it a little bit by passing around objects that represent "the type of result that I want", and use those as your dispatcher, but it's not really the same.
Multiple dispatch (example in Julia language) has similar purposes with type classes. Multiple dispatch provides compile-time polymorphism (just like type classes) while object interfaces in typical dynamic languages (i.e. Python) are usually limited to runtime polymorphism. Multiple dispatch provides better perfomance than usual interfaces you can see in dynamic object-oriented languages so it makes perfect sense in dynamic languages.
There are some multiple dispatch implementations for Python but I don't sure if they provide compile-time polymorpism.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With