Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What to do when a type contains itself?

Tags:

haskell

I have code that works for a monad that's constrained to have some state. I'm having a problem because the state has a type variable that requires the monad.

It looks like:

myget :: MonadState (MyState m A) m => m A

Now when I try to make it more specific, there's a problem. E.g. just with StateT (on some inner-monad im):

myget' :: StateT <loops here> im A
myget' :: StateT (MyState <loop> A) im A
myget' :: StateT (MyState (MyState <loop> A) A) im A
myget' :: StateT (MyState (MyState (MyState <loop> A) A) A) im A
...
myget' = myget

So obviously I can't write this type signature; I can't even leave it for type-inference.

How can I solve this?
I did kind of solve it by making myget (the first, general definition) work on a monad transformer instead, and it did work, but then the code doesn't play nicely with anything else (because usually people work with monads transformers as just monads), so it's not a really good solution.

Any ideas?

like image 234
MasterMastic Avatar asked Sep 28 '16 18:09

MasterMastic


People also ask

Can a structure contain itself?

A structure T cannot contain itself. How would you know its size? It would be impossible to do so, because the size of T would require you to know the size of T (because T contains another T ). This turns into an infinite recursion.

Can a class contain a reference to itself?

Because in Java, a variable of type abc doesn't contain an abc object. A variable of type abc contains a reference to an abc object. Your reasoning would be valid in say C++. But a class can have static object of self type.

Why can't a structure have an instance of itself?

Because it is impossible to create memory layout for such structure.

What can a structure not contain?

The book says, "A structure cannot contain an instance of itself. For example, a variable of type struct employee cannot be declared in the definition for struct employee .


1 Answers

newtype to the rescue! A newtype or data declaration can break a loop.

newtype MS s m a = MS
  {getMS :: StateT (MyState (MS s m) s) m a}
  deriving (Functor, Applicative, Monad)

deriving instance Monad m =>
  MonadState (MyState (MS s m) s) (MS s m)

instance MonadTrans (MS s) where
  lift = MS . lift
like image 74
dfeuer Avatar answered Oct 14 '22 18:10

dfeuer