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

时间:2013-07-06 22:51:49

标签: haskell polymorphism gadt haskell-pipes

这似乎是一个合理的想法,但我遇到类型麻烦。我希望有一个Client可以向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函数来将它们显示给用户。我希望能够改变一个,只要列表和功能匹配。

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

1 个答案:

答案 0 :(得分: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的列表,而不是使用存在量化技巧,但我把它包括在内只是为了表明如果你好奇的话会怎么做。