This seems like a reasonable thing to want, but I'm having type troubles. I'd like to have a Client
that can send a list of options to a Server
, which will choose one and return the chosen element. So something like this:
module Toy where
import Pipes
asker :: Monad m => () -> Client ([a], a -> String) a m ()
asker () = do
_ <- request ([0.0, 2.0], show)
_ <- request (["3", "4"], show)
return ()
The idea is that the server can call the a -> String
function on each element of the list to display them to a user. I'd like to be able to vary a, as long as the list and function match.
Is something like this possible? Maybe the constraints I want can be encoded into a GADT somehow?
You can't do it quite the way you asked, but you can cheat a little bit and get something that's almost as good:
{-# LANGUAGE ExistentialQuantification #-}
module Toy where
import Control.Monad
import Pipes
import Pipes.Prelude (foreverK)
data Request = forall a . Request [a] (a -> String)
asker :: Monad m => () -> Client Request Int m ()
asker () = do
_ <- request (Request [0.0, 2.0] show)
_ <- request (Request ["3", "4"] show)
return ()
server :: Request -> Server Request Int IO r
server = foreverK $ \req -> case req of
Request as f -> do
choice <- lift $ do
let select = do
putStrLn "Select an option"
forM_ (zip [0..] as) $ \(n, a) ->
putStrLn $ show n ++ ": " ++ f a
n <- readLn
if (n >= length as)
then do
putStrLn "Invalid selection"
select
else return n
select
respond choice
Instead of returning back the value selected, you return back an Int
corresponding to the index of the selected element. The rest is just using ExistentialQuantification
.
Like others recommended, I suggest that you actually just send a list of String
s instead of using the existential quantification trick, but I included it just to show how that would be done just in case you were curious.