3 ms·
Fleshing out my "other point": "Passing the dictionary as a record" is a pretty common alternative to typeclasses. The way it works is if you have a typeclass
by dllthomas 11y ago
Fleshing out my "other point":
"Passing the dictionary as a record" is a pretty common alternative to typeclasses. The way it works is if you have a typeclass:
class Foo a where
foo :: ...
bar :: ...
you instead make a record that looks like:
data Foo = Foo { foo :: ..., bar :: ... }
This works great for a lot of things, and is often preferable to typeclasses when all you're doing is defining an interface. One objection is that things look slightly less tidy, but the main problem with it (where it's a problem at all) is that there's no way of identifying individual implementors of an interface by type anymore. An example where this relevant is Set. We could define the Set operations to take a comparison function, but we couldn't be sure that all comparison functions agree across all interactions with a particular set.
What I mean by "reifying the instance" is indexing typeclasses with a (single constructor) type that identifies the instance, and then passing that around to let us select which instance we care about, even for the same underlying type.
For example:
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
import Data.Function (on)
class ParamOrd o a | o -> a where
pcompare :: o -> a -> a -> Ordering
data StringsOverLength = StringsOverLength
data StringsLexicographically = StringsLexicographically
data IntegersInOrder = IntegersInOrder
data IntegersReversed = IntegersReversed
data ReversedOrdering r = ReversedOrdering r
instance ParamOrd IntegersInOrder Integer where
pcompare _ = compare
instance ParamOrd (ReversedOrdering r) Integer where
pcompare o = flip (pcompare o)
instance ParamOrd StringsOverLength String where
pcompare _ = compare `on` length
instance ParamOrd StringsLexicographically String where
pcompare _ = compare
Now we could write a new version of Set, `ParamSet o a` such that we can still enforce agreement while choosing our orderings with an argument rather than a newtype.