Question

If I have the following two Kleisli arrows:

stdoutProcessA :: Kleisli Maybe String (IO String)
writeToFileA :: Kleisli Maybe (FilePath, String) (IO ())

I would like to be able to write someting like:

compile = proc src -> do
    output <- stdoutProcessA -< "..."
    writeToFileA -< ("...", output)
    ...

which of course doesn't work, because String doesn't match with IO String. On the other hand, it is possible to define both stdoutProcessA and writeToFileA to be of type Kleisli IO ..., but then I wouldn't be able to compose them with arrows of type Kleisli Maybe ..., which I need for other things.

I am not very experienced with arrows yet, so I'm probably missing something obvious. How would one go about doing the above?

Was it helpful?

Solution

These arrows don't make much sense to me:

stdoutProcessA :: Kleisli Maybe String (IO String)
writeToFileA :: Kleisli Maybe (FilePath, String) (IO ())

They represent functions with result Maybe (IO a), when you probably meant IO (Maybe a). The latter type represents IO actions which may fail, while in the former the failure or success cannot depend on the IO at all.

The correct way to combine IO and Maybe is to use the MaybeT monad transformer, like so:

stdoutProcessA :: Kleisli (MaybeT IO) String String
writeToFileA :: Kleisli (MaybeT IO) (FilePath, String) ()

If you write your other arrows as Monad m => Kleisli (MaybeT m) a b, they should compose nicely with these ones without any lifting. Alternatively, you can use

lift' :: Monad m => Kleisli Maybe a b -> Kleisli (MaybeT m) a b
lift' (Kleisli f) = Kleisli $ \x -> MaybeT (return $ f x)

to lift your existing Kleisli Maybe arrows to Kleisli (MaybeT IO) where needed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top