Re: [Haskell-cafe] Stuck on design problem

2013-05-20 Thread Miguel Mitrofanov
:t runMemLog (runTransitionT $ demo 1)
runMemLog (runTransitionT $ demo 1)
  :: MonadLog (MemLog a) () = Log a - ((), [Command ()])

That means, that foo, if you manage to compile it, would have type MonadLog 
(MemLog a) () = ((), [Command ()]). That means that in each call for foo it 
would be used as something of the type ((), [Command ()]), therefore giving no 
indication of which a should be used. The fact that there is only one 
instance of MonadLog (MemLog a) () - namely, the one with a = () - doesn't 
matter, as there could be others in the future. That's why GHC is complaining.

So, you have to provide such indication by youself, replacing IntMap.empty with 
(IntMap.empty :: Log ()).

20.05.2013, 15:36, Nicolas Trangez nico...@incubaid.com:
 All,

 Since I'm stuck on a coding problem and can't figure out how to proceed,
 I decided to call for help.

 I'm unable to get some code to typecheck, so maybe I'm missing something
 obvious on the implementation side, or more likely the design is
 completely wrong.

 Here's the idea: I have some code which uses some log of Entry a
 values (for some polymorphic type 'a'), and provides actions which
 output Command a values which should be interpreted by some wrapper
 code, e.g. adding some new entries to the log. These actions are
 implemented in a custom WriterT transformer (in this demo code, the
 original is more complex) to output Commands, while the inner monad
 should give access to the log entries (this could be in-memory like in
 the example, or stored on disk so using IO).

 You can find a trimmed-down version at
 https://gist.github.com/NicolasT/4230251f4f87f110d197

 This doesn't type-check, and I'm not sure how to proceed. Am I taking a
 wrong approach? Do I need a different design?

 Thanks,

 Nicolas

 ___
 Haskell-Cafe mailing list
 Haskell-Cafe@haskell.org
 http://www.haskell.org/mailman/listinfo/haskell-cafe

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Stuck on design problem

2013-05-20 Thread Adam Gundry
Hi Nicolas,

Your design doesn't look too unreasonable, though I haven't looked at in
detail. I do have a quick observation regarding the implementation that
I hope might help. Your gist defines

 class MonadLog m a where
   getEntry :: Index - m (Entry a)

 instance MonadLog (MemLog a) a

and then you hit the error

 No instance for (MonadLog (MemLog a0) ())

which is a tell-tale ambiguity problem. This is a common issue with
multi-parameter type classes. GHC cannot determine the existential
variable a0, because it will not commit to the instance for MemLog in
case a more specific instance turns up.

One option is to turn on GADTs or TypeFamilies and write

 instance a ~ a' = MonadLog (MemLog a) a'

which will allow the instance to match and generate the easily solved
constraint a0 ~ (). You may need to do the same for other instances.

Alternatively, you could add a functional dependency

 class MonadLog m a | m - a

or use a type family:

 class MonadLog' m where
   type Element m
   getEntry' :: Index - m (Entry (Element m))

 instance MonadLog' (MemLog a) where
   type Element (MemLog a) = a
   getEntry' i = flip (IntMap.!) i `fmap` ask


Hope this helps,

Adam


On 20/05/13 12:25, Nicolas Trangez wrote:
 All,
 
 Since I'm stuck on a coding problem and can't figure out how to proceed,
 I decided to call for help.
 
 I'm unable to get some code to typecheck, so maybe I'm missing something
 obvious on the implementation side, or more likely the design is
 completely wrong.
 
 Here's the idea: I have some code which uses some log of Entry a
 values (for some polymorphic type 'a'), and provides actions which
 output Command a values which should be interpreted by some wrapper
 code, e.g. adding some new entries to the log. These actions are
 implemented in a custom WriterT transformer (in this demo code, the
 original is more complex) to output Commands, while the inner monad
 should give access to the log entries (this could be in-memory like in
 the example, or stored on disk so using IO).
 
 You can find a trimmed-down version at
 https://gist.github.com/NicolasT/4230251f4f87f110d197
 
 This doesn't type-check, and I'm not sure how to proceed. Am I taking a
 wrong approach? Do I need a different design?
 
 Thanks,
 
 Nicolas
 
 
 ___
 Haskell-Cafe mailing list
 Haskell-Cafe@haskell.org
 http://www.haskell.org/mailman/listinfo/haskell-cafe
 
 


-- 
The University of Strathclyde is a charitable body, registered in
Scotland, with registration number SC015263.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Stuck on design problem

2013-05-20 Thread Nicolas Trangez
Miguel,

On Mon, 2013-05-20 at 16:38 +0400, Miguel Mitrofanov wrote:
 :t runMemLog (runTransitionT $ demo 1)
 runMemLog (runTransitionT $ demo 1)
   :: MonadLog (MemLog a) () = Log a - ((), [Command ()])
 
 That means, that foo, if you manage to compile it, would have type MonadLog 
 (MemLog a) () = ((), [Command ()]). That means that in each call for foo it 
 would be used as something of the type ((), [Command ()]), therefore giving 
 no indication of which a should be used. The fact that there is only one 
 instance of MonadLog (MemLog a) () - namely, the one with a = () - doesn't 
 matter, as there could be others in the future. That's why GHC is complaining.
 
 So, you have to provide such indication by youself, replacing IntMap.empty 
 with (IntMap.empty :: Log ()).

Thanks for the pointer. I tried using an explicit type-annotation myself
before as well, but that failed, and I found the root-cause: in my
original code, the type-signature of runTransitionT was all wrong,
instead of

  runTransitionT :: TransitionT a m a - m (a, [Command a])

this was intended to be

  runTransitionT :: TransitionT a m r - m (r, [Command a])

After making this change, and using an explicit type-signature for the
empty IntMap as you suggested, things work as expected, see
https://gist.github.com/NicolasT/4230251f4f87f110d197/revisions

In my original code, this didn't help out somehow (some other things at
play there as well), but another suggestion on this list did.

Thanks for the help!

Nicolas


 
 20.05.2013, 15:36, Nicolas Trangez nico...@incubaid.com:
  All,
 
  Since I'm stuck on a coding problem and can't figure out how to proceed,
  I decided to call for help.
 
  I'm unable to get some code to typecheck, so maybe I'm missing something
  obvious on the implementation side, or more likely the design is
  completely wrong.
 
  Here's the idea: I have some code which uses some log of Entry a
  values (for some polymorphic type 'a'), and provides actions which
  output Command a values which should be interpreted by some wrapper
  code, e.g. adding some new entries to the log. These actions are
  implemented in a custom WriterT transformer (in this demo code, the
  original is more complex) to output Commands, while the inner monad
  should give access to the log entries (this could be in-memory like in
  the example, or stored on disk so using IO).
 
  You can find a trimmed-down version at
  https://gist.github.com/NicolasT/4230251f4f87f110d197
 
  This doesn't type-check, and I'm not sure how to proceed. Am I taking a
  wrong approach? Do I need a different design?
 
  Thanks,
 
  Nicolas
 
  ___
  Haskell-Cafe mailing list
  Haskell-Cafe@haskell.org
  http://www.haskell.org/mailman/listinfo/haskell-cafe



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Stuck on design problem

2013-05-20 Thread Nicolas Trangez
Adam,

On Mon, 2013-05-20 at 13:37 +0100, Adam Gundry wrote:
 Hi Nicolas,
 
 Your design doesn't look too unreasonable, though I haven't looked at in
 detail. I do have a quick observation regarding the implementation that
 I hope might help. Your gist defines
 
  class MonadLog m a where
getEntry :: Index - m (Entry a)
 
  instance MonadLog (MemLog a) a
 
 and then you hit the error
 
  No instance for (MonadLog (MemLog a0) ())
 
 which is a tell-tale ambiguity problem. This is a common issue with
 multi-parameter type classes. GHC cannot determine the existential
 variable a0, because it will not commit to the instance for MemLog in
 case a more specific instance turns up.
 
 One option is to turn on GADTs or TypeFamilies and write
 
  instance a ~ a' = MonadLog (MemLog a) a'
 
 which will allow the instance to match and generate the easily solved
 constraint a0 ~ (). You may need to do the same for other instances.
 
 Alternatively, you could add a functional dependency
 
  class MonadLog m a | m - a
 
 or use a type family:
 
  class MonadLog' m where
type Element m
getEntry' :: Index - m (Entry (Element m))
 
  instance MonadLog' (MemLog a) where
type Element (MemLog a) = a
getEntry' i = flip (IntMap.!) i `fmap` ask
 

Thanks a bunch. Using FunDeps, things work as expected, also in my more
complicated original code. I chose the FunDeps approach because it seems
the least intrusive (no need to clutter instances).

Thanks a bunch for all help, this list is certainly one of the things
which makes writing Haskell code a very rewarding experience.

Thanks,

Nicolas


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe