Extensible Effects & Multiple Operations

I am playing around with the extensible-effects framework and cannot figure out how to solve this problem. I am trying to define a set of operations that only work after a file has been opened. For example, reading a character from a file or detecting EOF. My problem is I cannot figure out how to define one "runner" for my Effect that can deal with operations with different result types. For example, I would like my `readFrom` and `atEOF` operations to have the following types: data OpenFile r v = ... -- my "OpenFile" effect -- read a character from the file readFrom :: Eff r Char -- detect EOF atEOF :: Eff r Bool And I would like to use this operations as follows (where I read a byte from the file, check EOF, and return the concatenation of the two values): main = do c <- runOpenFile "Setup.hs" (do a <- readFrom -- `a` has `Char` type eof <- atEOF -- `eof` has `Bool` type return $ [a] ++ show eof) putStrLn c However, I cannot define a `runOpenFile` that compiles. For example, this definition gives me "Overlapping Instance" errors: runOpenFile :: FilePath -> Eff (OpenFile v :> r) result -> IO result The best I've come up with is to define a `Result` type that holds all possible results: data Result = AtEOF Bool | ReadChar Char The `Result` type then lets me put a single type on the `OpenFile` effect in `runOpenFile`: runOpenFile :: FilePath -> Eff (OpenFile Result :> r) result -> IO result But that makes my `main` program pretty ugly, because I have to deconstruct those result types each time: main = do c <- runOpenFile "Setup.hs" (do (ReadChar a) <- readFrom (AtEOF eof) <- atEOF return $ [a] ++ show eof) putStrLn c Does anyone have suggestions? Justin p.s. The complete code (in a sort-of similar form) can be seen at https://github.com/m4dc4p/ext-eff-sample/blob/master/src/OpenFile.hs

hi,
My problem is I cannot figure out how to define one "runner" for my Effect that can deal with operations with different result types.
afaict you have two possibilities. * `OpenFile` is essentially a `Reader Handle` and `readFrom :: (SetMember Lift IO r, Member OpenFile r) => Eff r Char` asks for the handle and works with that (in `IO`). * if you don't want to impose `SetMember Lift IO`, you will have to live with a sum type in your `OpenFile`, but not with `Result`. just use data OpenFile v = Read (Char -> v) | EOF (Bool -> v) deriving Typeable btw: i find working with `ScopedTypeVariables` easier than using your `asTypeOf`. but even then, you should maybe define your own prj' :: Union (OpenFile :> r) (VE (OpenFile :> r) result) -> Maybe (OpenFile (VE (OpenFile :> r) result)) prj' = prj iff you really need it, which you don't in this example. have fun with extensible effects, tob

On Thu, Jul 17, 2014 at 3:32 PM, Tobias Florek
data OpenFile v = Read (Char -> v) | EOF (Bool -> v) deriving Typeable
That worked! Removing the type variable (`a`) from `OpenFile` did the trick. I was carrying too much type information around for what I wanted to do (e.g., OpenFile Char and OpenFile Bool). Removing that extra piece of info allowed me to write `runOpenFile` just like I wanted. Thanks! Justin
participants (2)
-
Justin Bailey
-
Tobias Florek