我假設你想deserialised門票 不是運行他們做更多的事情,因爲如果不是你不妨詢問用戶提供了一堆String -> IO()
或類似的,根本不需要任何聰明的東西。
如果是這樣,萬歲!我不經常覺得它適合推薦這樣的高級語言功能。
class Ticketable a where
show' :: a -> String
read' :: String -> Maybe a
runTicket :: a -> IO()
-- other useful things to do with tickets
這一切都取決於read'
的類型。 read' :: Ticket a => String -> a
不是很有用, ,因爲它可以處理無效數據的唯一方法是崩潰。 如果我們更改類型爲read' :: Ticket a => String -> Maybe a
這可以允許我們從磁盤讀取和 嘗試所有的可能性或完全失敗。 (或者你可以使用一個解析器:parse :: Ticket a => String -> Maybe (a,String)
)
讓我們用一個GADT給我們ExistentialQuantification沒有語法和具備更好的錯誤信息:
{-# LANGUAGE GADTs #-}
data Ticket where
MkTicket :: Ticketable a => a -> Ticket
showT :: Ticket -> String
showT (MkTicket a) = show' a
runT :: Ticket -> IO()
runT (MkTicket a) = runTicket a
通知的MkTicket contstuctor如何提供上下文Ticketable a
爲自由! GADT很棒。
使Ticketable和Ticketable的實例很好,但這不起作用,因爲會隱藏 模糊a
隱藏在其中。讓我們來看看可讀取票務類型的函數,並讓它們讀取 票。
ticketize :: Ticketable a => (String -> Maybe a) -> (String -> Maybe Ticket)
ticketize = ((.).fmap) MkTicket -- a little pointfree fun
你可以使用一些不尋常的定點字符串,如 "\n-+-+-+-+-+-Ticket-+-+-+-Border-+-+-+-+-+-+-+-\n"
分離您的序列化的數據或更好,使用單獨的文件 乾脆。在這個例子中,我將使用「\ n」作爲分隔符。
readTickets :: [String -> Maybe Ticket] -> String -> [Maybe Ticket]
readTickets readers xs = map (foldr orelse (const Nothing) readers) (lines xs)
orelse :: (a -> Maybe b) -> (a -> Maybe b) -> (a -> Maybe b)
(f `orelse` g) x = case f x of
Nothing -> g x
just_y -> just_y
現在讓我們擺脫Just
S和忽略Nothing
S:
runAll :: [String -> Maybe Ticket] -> String -> IO()
runAll ps xs = mapM_ runT . catMaybes $ readTickets ps xs
讓我們做一個簡單的票,只是打印一些目錄
newtype Dir = Dir {unDir :: FilePath} deriving Show
readDir xs = let (front,back) = splitAt 4 xs in
if front == "dir:" then Just $ Dir back else Nothing
instance Ticketable Dir where
show' (Dir p) = "dir:"++show p
read' = readDir
runTicket (Dir p) = doesDirectoryExist p >>= flip when
(getDirectoryContents >=> mapM_ putStrLn $ p)
和內容更瑣碎的票
data HelloWorld = HelloWorld deriving Show
readHW "HelloWorld" = Just HelloWorld
readHW _ = Nothing
instance Ticketable HelloWorld where
show' HelloWorld = "HelloWorld"
read' = readHW
runTicket HelloWorld = putStrLn "Hello World!"
,然後把它放在一起:
myreaders = [ticketize readDir,ticketize readHW]
main = runAll myreaders $ unlines ["HelloWorld",".","HelloWorld","..",",HelloWorld"]
哦,宕,我有我的鍵盤:( –
只有美元和歐元鍵..或者,如果你想將其存儲在某種有限的地圖快查找,請按哈希鍵。 – AndrewC
除了不使用存在類型:) – singpolyma