3

I am trying to define a type with two parameters i and m. I want to specialize this type fixing two specific instances which fix the m parameter. At the moment I have the following definitions:

-- | ZadehMembership: represents a membership value between 0 and 1 with min and max operators
newtype ZadehMembership = Z Double deriving (Show, Eq, Ord, Num)

-- | PAMembership: represents a membership value between 0 and 1 with algebraic sum and product operators
newtype PAMembership = PA Double deriving (Show, Eq, Ord, Num)

-- | FuzzySet type
newtype FuzzySet i m = FS (Map.Map i m) deriving (Eq, Ord)

add :: (Ord i, Eq m, L.BoundedLattice m) => FuzzySet i m -> (i, m) -> FuzzySet i m
add (FS fs) (i, m) = if m == L.bottom then FS fs else FS (Map.insert i m fs)

fromList :: (Ord i, Eq m, L.BoundedLattice m) => [(i, m)] -> FuzzySet i m
fromList = foldl add empty

I use the FuzzySet definition in this way:

let fs = fromList [(1, Z 0.2), (2, Z 0.5)]

I want to define a Functor on the FuzzySet type, but I have some class constraints that must be satisfied on both type parameters i and m, but it is not possible. Is there a way to improve my type definitions in order to solve this problem?

Thank you.

escher
  • 113
  • 5
  • This seems to be a variation of the well-known problem "why is `Data.Set.Set` not a functor/monad ?". Short answer: unfortunately having type class constraints copes with the standard `Functor`. [Indexed functors](http://stackoverflow.com/questions/27771474/what-is-exactly-an-indexed-functor-in-haskell-and-what-are-its-usages) could cope with them, I think. – chi Jan 22 '16 at 12:05
  • I think that indexed functors could be a proper solution, but how can I use them? Thank you – escher Jan 22 '16 at 12:16
  • @chi Are you sure that notion of indexed functor is "exciting enough"? The type `imap :: IxFunctor f => (a -> b) -> f j k a -> f j k b` still doesn't give you a handle to hang any constraints on `j`, `k`, `a`, or `b` off of. I think he would rather need something like [`RFunctor`](http://hackage.haskell.org/package/rmonad-0.8.0.2/docs/Control-RMonad.html). – Daniel Wagner Jan 22 '16 at 23:11
  • @DanielWagner Not sure at all. I was hoping to use some `Constraint`-indexed functor, possibly exploiting some polykinding magic, but `IFunctor` is not such a beast, and mine was a wild guess. `RFunctor` may be an actually working choice. – chi Jan 23 '16 at 00:05

1 Answers1

1

Nobody's said it yet, but why not just use the derived Functor instance?

{-# LANGUAGE DeriveFunctor #-}
newtype FuzzySet i m = FS (Map.Map i m) deriving (Eq, Ord, Functor)

Rather than placing the constraints on the datatype or the instance, place them on the functions that use FuzzySet i m, like you've done for add. That way, though you may be able to create a FuzzySet i x for some x that doesn't fit the constraint, you'll only be able to do useful operations with FuzzySet i m where m does.

rampion
  • 87,131
  • 49
  • 199
  • 315