It's not really possible, as far as I can tell.
It's not really possible, as far as I can tell.
-- Monoid as a record type
type Monoid a = {
empty: a,
append: a -> a -> a
}
-- Using this to make a generic concatenator
mconcat : Monoid a -> [a] -> a
mconcat m = foldl m.append m.empty
-- Instance of Monoid for strings
MString : Monoid String
MString = {
empty = "",
append = (++)
}
-- Instance for ints
MInt : Monoid Int
MInt = {
empty = 0,
append = (+)
}
-- Use the generic function
unlines : [String] -> String
unlines = mconcat MString . intercalate "\n"
You'll note here that the actual function signature for mconcat looks almost exactly like its Haskell counterpart, just that the Monoid instance is a regular argument like any other.Of course the downside is that you have to pass in the instance argument to any "type class polymorphic" function, so you lose a bit of conciseness but not much in the way of expressiveness. And you actually gain a bit, because instances are explicit (for example, you could make an instance of Monoid Int which used 1 and (*) instead).
I'm not sure if this pattern is used anywhere in extant Elm code, but this is a common way to implement type classes under the hood in languages that support them, and the approach seems doable in elm.
I knew it's possible, s we discussed in the "Elm is wrong" comment thread though, this technique get's awkward quickly.