-
-
Save izmailoff/e11e1efef5f93d81333bba9fb54b3f57 to your computer and use it in GitHub Desktop.
Solving the Expression Problem with Haskell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE NamedFieldPuns #-} | |
-- The Expression Problem and my sources: | |
-- http://stackoverflow.com/questions/3596366/what-is-the-expression-problem | |
-- http://blog.ontoillogical.com/blog/2014/10/18/solving-the-expression-problem-in-clojure/ | |
-- http://eli.thegreenplace.net/2016/the-expression-problem-and-its-solutions/ | |
-- http://www.ibm.com/developerworks/library/j-clojure-protocols/ | |
-- To begin demonstrating the problem, we first need some | |
-- "legacy code" with datastructures and functionality: | |
-- data structures ("shapes") | |
data Triangle = Triangle {a::Double,b::Double,c::Double} | |
data Square = Square {edge::Double} | |
-- protocols | |
class Areable shape where | |
-- calculates the shape's area | |
area :: shape -> Double | |
class SelfAware shape where | |
-- returns the name of the shape | |
whoami :: shape -> String | |
-- implementations | |
instance Areable Triangle where | |
-- use Heron's formula to calculate area | |
area Triangle {a, b, c} = | |
let s = (a + b + c) / 2 | |
in sqrt (s * (s - a) * (s - b) * (s - c)) | |
instance SelfAware Triangle where | |
whoami _ = "Triangle" | |
instance Areable Square where | |
area Square {edge} = edge * edge | |
instance SelfAware Square where | |
whoami _ = "Square" | |
-- Solving the Expression Problem | |
-- 1. adding new functionality | |
-- 2. adding new datastructures (that play well with existing functionality) | |
-- 1. | |
-- a new protocol is invented: Perimeterable | |
-- can we add this new functionality without altering existing code ? | |
-- => yes we can ! | |
-- | |
class Perimeterable shape where | |
-- calculates the perimeter of the shape | |
perimeter :: shape -> Double | |
instance Perimeterable Triangle where | |
perimeter Triangle {a,b,c} = a + b + c | |
instance Perimeterable Square where | |
perimeter Square {edge} = edge * 4 | |
-- 2. | |
-- a new shape is discovered: Circle | |
-- can we add a this new shape without altering existing code ? | |
-- => yes we can ! | |
-- | |
data Circle = Circle { r :: Double } | |
instance Areable Circle where | |
area Circle {r} = pi * r ^ 2 | |
instance SelfAware Circle where | |
whoami _ = "Circle" | |
instance Perimeterable Circle where | |
perimeter Circle {r} = r * 2 | |
-- "tests" | |
-- > area (Triangle 1 1 1) | |
-- 0.4330127018922193 | |
-- > whoami (Triangle 1 1 1) | |
-- "Triangle" | |
-- > perimeter (Triangle 1 1 1) | |
-- 3.0 | |
-- > area (Square 2) | |
-- 4.0 | |
-- > whoami (Square 2) | |
-- "Square" | |
-- > perimeter (Square 2) | |
-- 8.0 | |
-- > area (Circle 3) | |
-- 28.274333882308138 | |
-- > whoami (Circle 3) | |
-- "Circle" | |
-- > perimeter (Circle 3) | |
-- 6.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment