Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining an instance for a composite type in Haskell

I have a type that has a mappend-like function but not a real mappend, so it is not a Semigroup. For instance:

data MyType = MyType Int deriving Show

myMerge :: MyType -> MyType -> Maybe MyType
myMerge (MyType x) (MyType y)
  | (x < 0) || (y < 0) = Nothing
  | otherwise          = Just $ MyType $ x + y

I always deal with MyType when it is wrapped in Maybe. I need semantics that would be perfectly represented if I could define a Semigroup instance on the "combined" type Maybe MyType like this:

instance Semigroup (Maybe MyType) where
  (Just x) <> (Just y) = myMerge x y
  Nothing  <> Nothing  = Nothing
  Nothing  <> (Just _) = Nothing
  (Just _) <> Nothing  = Nothing

I.e. when both parameters are Just's, I can get either a Just or Nothing, otherwise I always get Nothing. But this is not possible, I get an error:

All instance types must be of the form (T a1 ... an)

How can I represent the semantics that I need?

like image 421
crosser Avatar asked Aug 29 '19 23:08

crosser


People also ask

What is composite data type in Haskell?

A composite data type is constructed from other types. The most common composite data types in Haskell are lists and tuples.

What does () mean in Haskell?

() is very often used as the result of something that has no interesting result. For example, an IO action that is supposed to perform some I/O and terminate without producing a result will typically have type IO () .

What are function types in Haskell?

Functions can also be passed as arguments or returned (as we have seen). Their types are given in the type signature. *Main> :t map map :: (a -> b) -> [a] -> [b] *Main> :t filter filter :: (a -> Bool) -> [a] -> [a] flip_args :: (a -> b -> c) -> b -> a -> c flip_args f x y = f y x.

What does type mean in Haskell?

In Haskell, types are how you describe the data your program will work with.


1 Answers

The instance you defined is illegal because it is basically trying to define a different (partial) Semigroup instance for Maybe, but Maybe already has one. Instead, use a newtype wrapper:

newtype MaybeMyType = MaybeMyType (Maybe MyType)

instance Semigroup MaybeMyType where
  ...

You will have to interact with your type through this MaybeMyType wrapper in the cases where you want to use its Semigroup instance.

like image 143
amalloy Avatar answered Oct 12 '22 04:10

amalloy