2013-07-06 38 views
3

這似乎是一個合理的想要的,但我有類型的麻煩。我想有一個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中?

+2

什麼是服務器做請求?如果它甚至不知道它會得到什麼類型,它會怎麼做?如果只能將該類型轉換爲字符串(使用該函數),爲什麼不在第一種情況下傳遞字符串? – bennofs

+0

我想那是真的。如果不需要將字符串轉換回來,那就太好了,但這不是什麼大問題。 – ajp

+2

@ajp:是(a)所述客戶端發送的*符合一個接口(例如* *'Show')一些*類型值的想法; (b)服務器接受* any *這種類型的值; (c)當客戶端收到來自服務器的響應時,它知道它發送的是哪種類型?步驟(c)將成爲關鍵點(考慮如果服務器決定以相同的值響應兩次,或根本不響應)會發生什麼情況;你可能會想要一個總和類型或類似'Typeable' /'Dynamic'。存在(你在使用GADT時得到的東西)永遠不能被解開以瞭解原始類型。 –

回答

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的列表,而不是使用存在性量化技巧,但是我只是爲了說明如果你好奇而採取這種做法。

+0

謝謝!我確實已經用'[String]'去'Int' – ajp