2013-07-06 2 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 на каждом элементе списка, чтобы отобразить их пользователю. Я хотел бы иметь возможность изменять a, пока список и функция совпадают.

Возможно ли это как можно? Может быть, ограничения, которые я хочу, можно каким-то образом закодировать в GADT?

+2

Что делает сервер с запросом? Что он мог сделать, если даже не знал, какой тип он получит? Если он может преобразовать только этот тип в String (используя эту функцию), почему бы вам не передать строку в первом случае? – bennofs

+0

Я думаю, это правда. Было бы неплохо не преобразовать ответ из String, но это не огромная сделка. – ajp

+2

@ajp: Идея состоит в том, что (а) клиент отправляет значения типа * some *, которые соответствуют интерфейсу (* например, * '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 s вместо использования экзистенциального метода квантификации, но я включил его, чтобы показать, как это будет сделано на случай, если вам будет интересно.

+0

спасибо! Я действительно пошел с '[String]' на 'Int' – ajp

Смежные вопросы