haskus / packages

Haskus packages
https://haskus.org/
24 stars 11 forks source link

Does Excepts have a valid (ie. lawful) MonadUnliftIO instance? #20

Closed fonghou closed 4 years ago

fonghou commented 5 years ago

Hi, I'm curious whether Excepts has a valid MonadUnliftIO instance http://hackage.haskell.org/package/unliftio-core-0.1.2.0/docs/Control-Monad-IO-Unlift.html.

I'm not sure about whether Excepts type provides a solution to what's called "state discarding problem" in control functions, which is described here https://www.youtube.com/watch?v=KZIN9f9rI34&feature=youtu.be&t=794. It seems the problem for ExceptT is that two Left values can't unify, whereas Excepts type can.

Thanks!

hsyl20 commented 5 years ago

Hi,

I'm curious whether Excepts has a valid MonadUnliftIO instance http://hackage.haskell.org/package/unliftio-core-0.1.2.0/docs/Control-Monad-IO-Unlift.html.

Excepts has "state" in the sense Michael Snoyman gives in the talk (thanks for the link!) so we can't have a MonadUnliftIO instance for it.

I'm not sure about whether Excepts type provides a solution to what's called "state discarding problem" in control functions, which is described here https://www.youtube.com/watch?v=KZIN9f9rI34&feature=youtu.be&t=794. It seems the problem for ExceptT is that two Left values can't unify, whereas Excepts type can.

I have added a generic control function to combine two Excepts and retrieve any combination of state: https://github.com/haskus/packages/commit/abfe7c5b585c52197161f7637b7c279950649cdf#diff-b8ebfe274b24b5e11a5b53d9854479c8R368

We "unify" the left values with a product so the number of types may blow up, but it should work. Replace undefined with concurrently to execute in parallel.

> let f = throwE "a" :: Excepts '[String,Int] IO Bool
> let g = throwE 'x' :: Excepts '[Char,Double] IO Float
> :t runBothE undefined f g
runBothE undefined f g
  :: Excepts
       '[(Bool, Char), (Bool, Double), ([Char], Float), ([Char], Char),
         ([Char], Double), (Int, Float), (Int, Char), (Int, Double)]
       IO
       (Bool, Float)

They could do something similar with ExcepT but it would be ugly:

ExpectT e1 m a -> ExceptT e2 m b -> ExceptT (Either (e1,b) (Either (e1,e2) (a,e2))) m (a,b)

fonghou commented 5 years ago

That's interesting...

I'd expect that runBothE undefined f g has a more "flatten" type like Excepts '[String,Int,Char,Double] IO (Bool, Float).

I think this is to say throwE can't auto cancel concurrentE = runBothE concurrently.

Thanks!