3

这似乎是一件合理的事情,但我遇到了类型问题。我想要一个Client可以向 a 发送选项列表的 a 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 中?

4

1 回答 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.

像其他人推荐的那样,我建议你实际上只是发送一个Strings 列表而不是使用存在量化技巧,但我包含它只是为了展示如何做到这一点,以防万一你好奇。

于 2013-07-07T02:52:07.660 回答