阅读类型总和 [英] Read of types sum

查看:77
本文介绍了阅读类型总和的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  { - #LANGUAGE TypeOperators# - } 
infixr 9 |||
数据a ||| b = A a | B b导出显示
- 或者这个:
- 数据a ||| b = N | A a(a ||| b)| B b(a ||| b)派生(Data,Show)

实例(读取a,读取b)=>阅读(a || b)其中
readPrec = parens $ do
a< - (A< $> readPrec)< |> (B $ readPrec)
- OR:
- a< - (flip A N< $> readPrec)< |> (flip BN< $> readPrec)
return a

如果我想阅读一些内容:

 >阅读'a':: Int ||| Char ||| String 
B(A'a')

但是如何处理这种奇怪的类型?我想将它折叠到 Int Char 或 String ...或另一个,但原子(标量/简单)。最终目标是将1,'a'等字符串读取到列表中,如 [D 1,D'a'] 。这里的主要约束是结构是灵活的,所以字符串可以是1,'a''a',1 code>或\xxx \,1,2,'a'。我知道如何阅读用分隔符分隔的东西,但这些东西应该作为类型传递,而不是像 C Char | I Int | S String | etc 类型的总和。可能吗?或者没有办法完成它没有类型的总和?

解决方案

没有办法做到这一点一般使用读取,因为相同的输入字符串可能正确解析为多个有效类型。但是,您可以使用像 Text.Read.readMaybe 这样的函数执行此操作,该函数会在模糊输入中返回 Nothing 。您可能还会返回一个元组或有效解释列表,或者有一个规则来尝试解析这些类型,例如:尝试按照声明的顺序解析每个类型。



下面是一些示例代码,作为概念验证:

$ p $ import $ Data.Maybe(catMaybes,fromJust ,isJust,isNothing)
import qualified Text.Read

data AnyOf3 abc = FirstOf3 a | SecondOf3 b | ThirdOf3 c

instance(Show a,Show b,Show c)=>显示(AnyOf3 a b c)其中
显示(FirstOf3 x)= show x - 可以从模式守护程序中推断出类型。
show(SecondOf3 x)= show x
show(ThirdOf3 x)= show x
$ b $ main main :: IO()
main =
(putStrLn 。unwords。map show。catMaybes。map readDBS)
[True,2,\foo \,bar]>>
(putStrLn.unwords.map show。readIID)100

readMaybe'::(读取a,读取b,读取c)=>字符串 - >也许(AnyOf3 a b c)
- 基于Text.Read
的函数readMaybe'x |是一个&&没有b&&没有c =
(Just。FirstOf3。fromJust)a - 可以从中推断出a的类型。
| is not a& amp;&是只有b&&没有c =
(Just。SecondOf3。fromJust)b - 可以从中推断出b的类型。
| is not a& amp;&没有b&& is just c =
(Just。ThirdOf3。fromJust)c - 可以从中推断出c的类型。
|否则=无
其中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 ::(读取a,读取b,读取c)=>字符串 - > [AnyOf3 a b c]
readToList x =重新包装FirstOf3 x ++重新包装SecondOf3 x ++重新包装ThirdOf3 x
重新构建构造函数y | isJust z = [(constructor.fromJust)z]
|否则= []
其中z = Text.Read.readMaybe y

readIID :: String - > [AnyOf3 Int Integer Double]
readIID = readToList

第一个输出行回显每个输入解析成功,即布尔常量,数字和带引号的字符串,但不是 bar 。第二条输出行反映了对输入的每种可能的解释,即100作为 Int Integer 和a Double



对于更复杂的事情,您希望编写一个解析器。 Haskell有一些非常好的库可以将它们从combinators中构建出来。你可以看看Parsec之类的。但是,了解内幕情况仍然很有帮助。


When I want to read string to type A I write read str::A. Consider, I want to have generic function which can read string to different types, so I want to write something like read str::A|||B|||C or something similar. The only thing I could think of is:

{-# 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

And if I want to read something:

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

But what to do with such weird type? I want to fold it to Int or to Char or to String... Or to something another but "atomic" (scalar/simple). Final goal is to read strings like "1,'a'" to list-like [D 1, D 'a']. And main constraint here is that structure is flexible, so string can be "1, 'a'" or "'a', 1" or "\"xxx\", 1, 2, 'a'". I know how to read something separated with delimiter, but this something should be passed as type, not as sum of types like C Char|I Int|S String|etc. Is it possible? Or no way to accomplish it without sum of types?

解决方案

There’s no way to do this in general using read, because the same input string might parse correctly to more than one of the valid types. You could, however, do this with a function like Text.Read.readMaybe, which returns Nothing on ambiguous input. You might also return a tuple or list of the valid interpretations, or have a rule for which order to attempt to parse the types in, such as: attempt to parse each type in the order they were declared.

Here’s some example code, as proof of concept:

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

The first output line echoes every input that parsed successfully, that is, the Boolean constant, the number and the quoted string, but not bar. The second output line echoes every possible interpretation of the input, that is, 100 as an Int, an Integer and a Double.

For something more complicated, you want to write a parser. Haskell has some very good libraries to build them out of combinators. You might look at one such as Parsec. But it’s still helpful to understand what goes on under the hood.

这篇关于阅读类型总和的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆