#Monoid in Scala by programmers from different backgrounds#
In spirit of The Evolution of a Haskell Programmer. Originally stolen from isoresursive.
#Monoid in Scala by programmers from different backgrounds#
In spirit of The Evolution of a Haskell Programmer. Originally stolen from isoresursive.
// Haskeller | |
trait Monoid[T] { | |
val id: T | |
def op: T => T => T | |
} | |
// Agdaista | |
trait Monoid[T] { | |
val `∅`: T | |
def `∙`: T ⇒ T ⇒ T | |
// since scala 2.11, using some shapeless magic (https://gist.github.com/folone/4945168) | |
//implicit val leftId: ^(∅ ∙ x) = x | |
//implicit val rightID: ^(x ∙ ∅) = x | |
} | |
// ML-dev | |
trait Monoid { | |
type T | |
val id: T | |
def op: (T, T) => T | |
} | |
// Hardcore ML-dev | |
type MONOID = { | |
type T | |
val id: T | |
def op: (T, T) => T | |
} | |
// Java-guy, after reading about self-types | |
trait Monoidal[T] { this: T => | |
def op(x: T): T | |
} | |
// Java-guy, after reading about implicit views | |
abstract class MonoidEnriched[T] { | |
def op(y: T): T | |
} | |
// Java-guy, after reading about typeclasses | |
trait Monoid[T] { | |
val id: T | |
def op(x: T, y: T): T | |
} | |
// Java-guy, after reading about currying and partial application | |
trait Monoid[T] { | |
val id: T | |
def op(x: T)(y: T): T | |
} |
// Haskeller | |
implicit def list[T] = new Monoid[List[T]] { | |
val id = Nil | |
def op = xs => xs ++ _ | |
} | |
// ML-dev | |
implicit def list[E] = new Monoid { | |
type T = List[E] | |
val id = Nil | |
def op = _ ++ _ | |
} | |
// Hardcore ML-dev | |
implicit def list[E]: MONOID { type T = List[E] } = new { | |
type T = List[E] | |
val id = Nil | |
def op = _ ++ _ | |
} | |
// Java-guy, after reading about self-types | |
class MonoidalListAdapter[T](val list: List[T]) extends Monoidal[MonoidalListAdapter[T]] { | |
def op(x: MonoidalListAdapter[T]) = new MonoidalListAdapter[T](list ++ x.list) | |
} | |
// Java-guy, after reading about implicit views | |
abstract class ListMonoidEnriched[T](x: List[T]) extends MonoidEnriched[List[T]] { | |
def op(y: List[T]) = x ++ y | |
} | |
implicit def list[T](l: List[T]) = new ListMonoidEnriched(l) | |
// Java-guy, after reading about implicit classes | |
implicit class ListMonoidEnriched[T](x: List[T]) extends MonoidEnriched[List[T]] { | |
def op(y: List[T]) = x ++ y | |
} | |
// Java-guy, after reading about typeclasses | |
implicit def list[T] = new Monoid[List[T]] { | |
val id = Nil | |
def op(x: List[T], y: List[T]) = x ++ y | |
} | |
// Java-guy, after reading about currying and partial application | |
implicit def list[T] = new Monoid[List[T]] { | |
val id = Nil | |
def op(x: List[T])(y: List[T]) = x ++ y | |
} |
// Typeclass-guys | |
def f[M](xs: M)(implicit m: Monoid[M]) = m.op(xs, xs) // или m.op(xs)(xs) | |
// Hardcore ML-dev | |
def f[M](xs: M)(implicit m: MONOID { type T = M }) = { | |
import m._ | |
op(xs, xs) | |
} | |
// Java-guy, after reading about self-types | |
def f[M <: Monoidal[M]](xs: M) = xs.op(xs) | |
// Implicit views and classes guys | |
def f[M <% MonoidEnriched[M]](xs: M) = xs.op(xs) |
They all suffer from failure to split the binary operation. The realisation of the importance of this comes about from having a background in application development.