Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use polymorphism in functional programming? [closed]

How to use polymorphism in functional programming (with dynamic type system)?

Let's consider following example (first in OOP second in FP). The program is very simple - there are list of figures and we need to draw all of them, different figures use different drawing algorithms.

In OOP it can be done trivially, but how to do it in FP? Especially in languages with dynamic type system, like Scheme, Clojure (without static type resolving at compile time)?

I created simple code ( live version http://tinkerbin.com/0C3y8D9Z , press 'Run' button ). I used if/else switch in FP sample, but it's a very bad approach. How such problem can be solved better?

Samples are in JavaScript, but it's only for purpose of simplicity, it would be interesting to see a solution in any functional language with dynamic typing system.

OOP

var print = function(message){document.write(message + "\n<br/>")}

// Object Oriented Approach.
var circle = {
  draw: function(){print("drawing circle ...")}
}
var rectangle = {
  draw: function(){print("drawing rectangle ...")}
}

var objects = [circle, rectangle]
objects.forEach(function(o){
  o.draw()
})

FP

var print = function(message){document.write(message + "\n<br/>")}

// Functional Approach.
var circle = {type: 'Circle'}
var drawCircle = function(){print("drawing circle ...")}

var rectangle = {type: 'Rectangle'}
var drawRectangle = function(){print("drawing rectangle ...")}

var objects = [circle, rectangle]
objects.forEach(function(o){
  if(o.type == 'Circle') drawCircle(o)
  else if(o.type == 'Rectangle') drawRectangle(o)
  else throw new Error('unknown type!')
})
like image 725
Alex Craft Avatar asked Nov 20 '12 16:11

Alex Craft


People also ask

Does functional programming have polymorphism?

In statically typed languages, this binding can usually be done at compile time (i.e., exhibiting early binding). The object oriented programming community often calls this type of polymorphism generics or generic programming. The functional programming community often calls this simply polymorphism.

Which type of function can be used for polymorphism?

6. Which type of function among the following shows polymorphism? Explanation: Only virtual functions among these can show polymorphism.

What is the primary advantage of polymorphism?

Advantages of PolymorphismIt helps the programmer to reuse the codes, i.e., classes once written, tested and implemented can be reused as required. Saves a lot of time. Single variable can be used to store multiple data types. Easy to debug the codes.


2 Answers

Your "FP" version is not what I consider the idiomatic FP example. In FP, you often use variants and pattern matching where in OOP you'd use classes and method dispatch. In particular, you only have one draw function that already does the dispatch internally:

var circle = {type: 'Circle'}
var rectangle = {type: 'Rectangle'}

var draw = function(shape) {
  switch (shape.type) {
    case 'Circle': print("drawing circle ..."); break
    case 'Rectangle': print("drawing rectangle ..."); break
  }
}

var objects = [circle, rectangle]
objects.forEach(draw)

(Of course, that is JavaScript. In a functional language you typically have much more elegant and concise syntax for this, e.g.:

draw `Circle    = print "drawing circle..."
draw `Rectangle = print "drawing rectangle..."

objects = [`Circle, `Rectangle]
foreach draw objects

)

Now, the average OO aficionado will see the above code and say: "But the OO solution is extensible, the above is not!" That's true in the sense that you can easily add new shapes to the OO version and don't have to touch any of the existing ones (or their draw functions) when you do. With the FP way, you'd have to go in and extend the draw function, and all other operations that may exist.

But what those people fail to see is that the converse is also true: the FP solution is extensible in a way the OO one isn't! Namely, when you add a new operation over your existing shapes then you don't need to touch any of the shape definitions, nor existing operations. You simply add another function, whereas with OO, you have to go and modify every class or constructor to include an implementation for the new operation.

That is, there is a dualism here in terms of modularity. The ideal, achieving simultaneous extensibility along both axes is known in literature as "the expression problem", and while various solutions exist (especially in functional languages), they are typically more complex. Hence, in practice you'll often want to decide for one dimension, depending on which dimension is more likely to matter for the problem at hand.

There are other advantages to the functional version. E.g it trivially scales to multi-dispatch or more complex case distinctions. It also is preferable when implementing an algorithm that is complicated and where the different cases are interrelated, so that you want to have the code in one place. As a rule of thumb, whenever you start using the visitor pattern in OO, a functional-style solution would have been more appropriate (and far, far easier).

Some further remarks:

  • This different preference in program organisation isn't the central idea of FP. What matters more is discouraging mutable state, and encouraging highly reusable higher-order abstractions.

  • The OO community has this habit of inventing new (buzz)words for every old idea. Its use of the term "polymorphism" (which is completely different from what it means elsewhere) is one such example. It says little more than being able to call functions without statically knowing what the callee is. You can do that in any language where functions are first-class values. In that sense, your OO solution is perfectly functional as well.

  • Your question has very little to do with types. Both the idiomatic OO and the idiomatic FP solution work in an untyped or typed language.

like image 157
Andreas Rossberg Avatar answered Oct 01 '22 15:10

Andreas Rossberg


OO polymorphism is not a part of functional programming. However some functional languages (e.g. clojure) have oo polymorphism.

Another kind of polymorphism is multimethods

(def circle {:type :circle
             :radius 50})

(def rectangle {:type :rectangle
                :width 5
                :height 10})

(defmulti draw :type)

(defmethod draw :circle [object]
  (println "circle: radius = " (:radius object)))

(defmethod draw :rectangle [object]
  (println "rectangle: "
           "width = " (:width object)
           "height = " (:height object)))

(doseq [o [rectangle circle]] (draw o))
=> rectangle:  width =  5 height =  10
   circle: radius =  50

Or you just can use functional style

(defn circle [] (println "drawing circle ..."))
(defn rectangle [] (println "drawing rectangle ..."))

(def objects [circle rectangle])

(doseq [o objects] (o))
=> drawing circle ...
   drawing rectangle ...
like image 44
mobyte Avatar answered Oct 01 '22 15:10

mobyte