从字符的文件列表或整数列表中读取

时间:2016-01-30 07:43:06

标签: haskell

我有一个问题。从元组的文件列表中读取有什么解决方案吗?取决于内容? 我知道,如果我需要读取整数,我会做类似的事情:

toTuple :: [String] -> [(Int,Int)]
toTuple = map (\y -> read y ::(Int,Int))

但是在文件中我可以有这种元组(int,int)或(char,int)。有什么方法可以做到这一点好吗?

我试图首先找到这个标志“'”。如果是,那么阅读字符,但由于某种原因它不起作用。

[编辑]

为了对元组起作用,我给元组赋予字符串,然后我用空格符号分割行。

输入示例:

Case 1 : ["(1,2)", "(1,3)" ,"(3,4)" ,"(1,4)"]
Case 2 : ["('a',2)", "('b',3)", "('g',8)", "('h',2)", "('r',4)"]

2 个答案:

答案 0 :(得分:4)

试试两个并选择成功:

readListWithMaybe :: Read a => String -> [String] -> Maybe [a]
readListWithMaybe s ss = fmap (: map read ss) (readMaybe s)

toTuple :: [String] -> Either [(Int, Int)] [(Char, Int)]
toTuple  []    = Left []
toTuple (s:ss) = fromJust $ readListWithMaybe s ss `choose` readListWithMaybe s ss

这是一个效率更高(且不安全)的版本:

toTuple

toTuple :: [String] -> Maybe (Either [(Int, Int)] [(Char, Int)]) toTuple ss = readListMaybe ss `choose` readListMaybe ss

的第一个定义中
readListMaybe

readListMaybe :: Read a => [String] -> Maybe [a] readListMaybe = mapM readMaybe 太严格了:

mapM

sequence是根据(>>=)定义的,Maybess对{{1}} monad严格定义的。此外,对{{1}}的提及也需要很长时间。第二个版本没有这些问题。

答案 1 :(得分:2)

正如我所说,考虑使用解析库可能是一个好主意,如果手头的任务变得有点复杂。

首先,您可以获得错误消息,如果您决定切换到自我声明的数据类型,它仍然很容易适用(当然稍作修改)。 同样从ByteString切换到Text(这两者都优于使用String)只是(不)评论4行

如果你没有兴趣使用它,这是一些例子。

我会在今天晚些时候解释它 - 因为我现在必须离开。

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Data.Attoparsec.ByteString.Char8
import Data.ByteString.Char8 as X
-- import Data.Attoparsec.Text
-- import Data.Text as X

main :: IO ()
main = do print <$> toTuples $ X.unlines ["(1,2)","(1,3)","(3,4)","(1,4)"]
          print <$> toTuples $ X.unlines ["('a',2)","('h',2)","('r',4)"]
          print <$> toTuples $ X.unlines ["('a',2)","(1,3)","(1,4)"] --works
          print <$> toTuples $ "('a',2)"   -- yields Right [Right ('a',2)]!!
          print <$> toTuples $ "(\"a\",2)" -- yields Right []!!

toTuples = parseOnly (myparser `sepBy` skipSpace :: Parser [Either (Int,Int) (Char,Int)])
  where myparser :: Parser (Either (Int,Int) (Char,Int))
        myparser = eitherP (tupleP decimal decimal)
                           (tupleP charP decimal)
        charP = do char '\''
                   c <- notChar '\''
                   char '\''
                   return c

tupleP :: Parser a -> Parser b -> Parser (a, b)
tupleP a b = do char '('
                a' <- a
                skipSpace
                char ','
                skipSpace
                b' <- b
                char ')'
                return (a',b')

编辑:说明

Parser是一个monad,所以它带有do - 符号,它使我们能够以这种非常方便的形式编写tupleP函数。同样适用于charP - 我们描述了在attoparsec库给出的原语中要解析的内容

它的内容类似于

  • 首先要求报价
  • 然后不允许引用的内容
  • 和另一个引用
  • 返回不引用的东西

如果你可以非正式地写下解析器,你很可能在编写haskell代码的过程中,唯一要做的就是找到库中的原语或者写一些辅助函数,如tupleP

一个好处是Parsers(monad)很好地组合,所以我们得到了我们想要的解析器eitherP (tupleP ..) (tupleP ..)

print <$>..行中发生的唯一魔力是Either是一个仿函数,使用<$>fmap的每个函数都使用Right Either s。

最后要注意的是sepBy返回一个列表 - 所以在解析失败的情况下,如果你想看到失败的使用sepBy1,我们仍会得到一个空列表!