I guess the following probably works. As per the comments, it's still a terrible, terrible, terrible idea. If you really want to write Haskell like this, then you don't really want to write Haskell.
Anyway, the idea is to provide a type class for:
insert :: (Ord k) => k -> v -> a
parameterized in all three parameters with a functional dependency specifying that a
determines k
and v
. In your case, a ~ (Map k' v' -> Map k' v')
implies k ~ k'
and v ~ v'
, while a ~ Set t
implies k ~ t
and v ~ Set t
.
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies,
NoMonomorphismRestriction #-}
module UnifiedInsert where
-- insert :: Ord k => k -> v -> Map k v -> Map k v
-- insert :: Ord a => a -> Set a -> Set a
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set
class Insert k v a | a -> k, a -> v where
insert :: (Ord k) => k -> v -> a
instance Insert k (Set k) (Set k) where
insert = Set.insert
instance Insert k v (Map k v -> Map k v) where
insert = Map.insert
fromList = foldr insert mempty
foo1 :: Set Int
foo1 = fromList [1..10]
Note that the type checker can deduce the type of the function fromList
(even if foo1
is dropped from the program), as long as the monomorphism restriction is off. It will have the rather preposterous type:
fromList :: (Foldable t, Insert k v v, Ord k, Monoid v) => t k -> v
which can, indeed, be specialized to Ord a => [a] -> Set a
, as required.