阅读类型总和

时间:2017-11-30 15:55:29

标签: haskell

当我想读取字符串以输入A时,我写read str::A。考虑一下,我希望有一个泛型函数可以读取不同类型的字符串,所以我想写一些像read str::A|||B|||C或类似的东西。我唯一能想到的是:

{-# LANGUAGE TypeOperators #-}
infixr 9 |||
data a ||| b = A a|B b deriving Show
-- OR THIS:
-- data a ||| b = N | A a (a ||| b) | B b (a ||| b) deriving (Data, Show)

instance (Read a, Read b) => Read (a ||| b) where
  readPrec = parens $ do
    a <- (A <$> readPrec) <|> (B <$> readPrec)
    -- OR:
    -- a <- (flip A N <$> readPrec) <|> (flip B N <$> readPrec)
    return a

如果我想读点什么:

> read "'a'"::Int|||Char|||String
B (A 'a')

但这种奇怪的类型怎么办?我想将它折叠到IntCharString ......或者折叠到另一个但是“原子”(标量/简单)。最终目标是将类似"1,'a'"的字符串读取为类似列表的[D 1, D 'a']。这里的主要约束是结构是灵活的,因此字符串可以是"1, 'a'""'a', 1""\"xxx\", 1, 2, 'a'"。我知道如何读取用分隔符分隔的内容,但是这个内容应该作为类型传递,而不是像C Char|I Int|S String|etc这样的类型的总和。可能吗?或没有办法在没有类型总和的情况下完成它?

1 个答案:

答案 0 :(得分:2)

使用Text.Read.readMaybe无法使用一般,因为相同的输入字符串可能会正确解析为多个有效类型。但是,您可以使用Nothing之类的函数执行此操作,该函数会在模糊输入上返回import Data.Maybe (catMaybes, fromJust, isJust, isNothing) import qualified Text.Read data AnyOf3 a b c = FirstOf3 a | SecondOf3 b | ThirdOf3 c instance (Show a, Show b, Show c) => Show (AnyOf3 a b c) where show (FirstOf3 x) = show x -- Can infer the type from the pattern guard. show (SecondOf3 x) = show x show (ThirdOf3 x) = show x main :: IO () main = (putStrLn . unwords . map show . catMaybes . map readDBS) ["True", "2", "\"foo\"", "bar"] >> (putStrLn . unwords . map show . readIID) "100" readMaybe' :: (Read a, Read b, Read c) => String -> Maybe (AnyOf3 a b c) -- Based on the function from Text.Read readMaybe' x | isJust a && isNothing b && isNothing c = (Just . FirstOf3 . fromJust) a -- Can infer the type of a from this. | isNothing a && isJust b && isNothing c = (Just . SecondOf3 . fromJust) b -- Can infer the type of b from this. | isNothing a && isNothing b && isJust c = (Just . ThirdOf3 . fromJust) c -- Can infer the type of c from this. | otherwise = Nothing where a = Text.Read.readMaybe x b = Text.Read.readMaybe x c = Text.Read.readMaybe x readDBS :: String -> Maybe (AnyOf3 Double Bool String) readDBS = readMaybe' readToList :: (Read a, Read b, Read c) => String -> [AnyOf3 a b c] readToList x = repack FirstOf3 x ++ repack SecondOf3 x ++ repack ThirdOf3 x where repack constructor y | isJust z = [(constructor . fromJust) z] | otherwise = [] where z = Text.Read.readMaybe y readIID :: String -> [AnyOf3 Int Integer Double] readIID = readToList 。您还可以返回有效解释的元组或列表,或者具有尝试解析类型的顺序的规则,例如:尝试按照声明的顺序解析每个类型。

以下是一些示例代码,作为概念证明:

bar

第一个输出行回显每个成功解析的输入,即布尔常量,数字和引用的字符串,但不是Int。第二个输出行回应输入的每个可能解释,即100 IntegerDouble/Library/LaunchDeamon

对于更复杂的东西,你想写一个解析器。 Haskell有一些非常好的库可以用组合器构建它们。你可能会看一下像Parsec这样的人。但是,了解幕后发生的事情仍然有帮助。