首页 文章

具有动态请求/响应类型的管道?

提问于
浏览
3

这似乎是一个合理的想法,但我希望'm having type troubles. I'能够发送一个选项列表到 Server ,它将选择一个并返回所选元素 . 所以像这样:

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 ()

这个想法是服务器可以在列表的每个元素上调用 a -> String 函数来将它们显示给用户 . 只要列表和功能匹配,我希望能够改变a .

这样的事情可能吗?也许我想要的约束可以以某种方式编码成GADT?

1 回答

  • 4

    你不能按照你提出的方式做到这一点,但你可以做一点作弊并获得几乎同样好的东西:

    {-# 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
    

    您将返回与所选元素的索引相对应的 Int ,而不是返回所选的值 . 其余的只是使用 ExistentialQuantification .

    像其他人推荐的那样,我建议你实际上只是发送一个 String 的列表,而不是使用存在量化技巧,但我把它包括在内只是为了表明如果你好奇的话会怎么做 .

相关问题