Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 非常简单的sexp解析器_Ruby_Parsing_Haskell - Fatal编程技术网

Ruby 非常简单的sexp解析器

Ruby 非常简单的sexp解析器,ruby,parsing,haskell,Ruby,Parsing,Haskell,对于赋值,我们必须实现一个非常基本的sexp解析器,这样对于输入,比如: "((a b) ((c d) e) f)" 它将返回: [["a", "b"], [["c", "d"], "e"], "f"] 因为这是一个更大赋值的一部分,所以只给解析器提供有效的输入(匹配parens&c)。我用Ruby提出了以下解决方案: def parse s, start, stop tokens = s.scan(/#{Regexp.escape(start)}|#{Regexp.escape(sto

对于赋值,我们必须实现一个非常基本的sexp解析器,这样对于输入,比如:

"((a b) ((c d) e) f)"
它将返回:

[["a", "b"], [["c", "d"], "e"], "f"]
因为这是一个更大赋值的一部分,所以只给解析器提供有效的输入(匹配parens&c)。我用Ruby提出了以下解决方案:

def parse s, start, stop
  tokens = s.scan(/#{Regexp.escape(start)}|#{Regexp.escape(stop)}|\w+/)

  stack = [[]]

  tokens.each do |tok|
    case tok
    when start
      stack << []
    when stop
      stack[-2] << stack.pop
    else
      stack[-1] << tok
    end
  end

  return stack[-1][-1]
end
def解析,开始,停止
tokens=s.scan(/#{Regexp.escape(开始)}|{Regexp.escape(停止)}|\w+/)
堆栈=[]]
代币。每个都有|
凯斯托克
什么时候开始

stackHaskell中惯用的方法是使用组合词解析

网上有很多例子,包括

  • 或者
在haskell中没有有效的类型(因为列表的所有元素在haskell中都必须是相同的类型),因此您需要为嵌套列表定义自己的数据结构,如下所示:

data NestedList = Value String | Nesting [NestedList]
parse = fst . parse'

parse' (LPar : tokens) =
    let (inner, rest) = parse' tokens
        (next, outer) = parse' rest
    in
      (Nesting inner : next, outer)
parse' (RPar : tokens) = ([], tokens)
parse' ((Symbol str) : tokens) =
    let (next, outer) = parse' tokens in
    (Value str : next, outer)
parse' [] = ([],[])
现在,如果您有一个令牌列表,其中令牌被定义为
data Token=LPar | RPar | Symbol String
,您可以将其解析为一个嵌套列表,如下所示:

data NestedList = Value String | Nesting [NestedList]
parse = fst . parse'

parse' (LPar : tokens) =
    let (inner, rest) = parse' tokens
        (next, outer) = parse' rest
    in
      (Nesting inner : next, outer)
parse' (RPar : tokens) = ([], tokens)
parse' ((Symbol str) : tokens) =
    let (next, outer) = parse' tokens in
    (Value str : next, outer)
parse' [] = ([],[])

虽然像Parsec这样的高级解析器很不错,但您并不真正需要所有这些功能 对于这个简单的例子。经典的解析方法是使用
读取
从前奏曲中键入。这也是你给性伴侣a型的方式
读取
实例

至少对这种风格有点熟悉是件好事 解析,因为在 标准库

这里有一个经典风格的简单解决方案:

import Data.Char (isSpace)

data Sexp = Atom String | List [Sexp]
  deriving (Eq, Ord)

instance Show Sexp where
  show (Atom a ) = a
  show (List es) = '(' : unwords (map show es) ++ ")"

instance Read Sexp where
  readsPrec n (c:cs) | isSpace c = readsPrec n cs
  readsPrec n ('(':cs)           = [(List es, cs') |
                                      (es, cs') <- readMany n cs]
  readsPrec _ (')':_)            = error "Sexp: unmatched parens"
  readsPrec _ cs                 = let (a, cs') = span isAtomChar cs
                                   in [(Atom a, cs')]

readMany :: Int -> ReadS [Sexp]
readMany _ (')':cs) = [([], cs)]
readMany n cs       = [(e : es, cs'') | (e, cs') <- readsPrec n cs,
                                        (es, cs'') <- readMany n cs']

isAtomChar :: Char -> Bool
isAtomChar '(' = False
isAtomChar ')' = False
isAtomChar c   = not $ isSpace c
导入数据.Char(isSpace) 数据Sexp=原子字符串|列表[Sexp] 推导(Eq,Ord) 实例Show Sexp where 显示(原子a)=a 显示(列表es)='(':UNWORD(地图显示es)+')” 实例Read Sexp where readsPrec n(c:cs)| isSpace c=readsPrec n cs readsPrec n('(':cs)=[(列表es,cs')| (es,cs')读[Sexp] readMany(')':cs)=[([],cs]
readMany n cs=[(e:es,cs')|(e,cs'))谢谢,唐,对于快速回复,我应该补充说我对一个不涉及像parsec这样的LIB的解决方案感兴趣。我将相应地编辑问题,并查看链接的答案。谢谢,这正是我所寻找的示例。惯用的解决方案是使用解析器库(combinator或其他)既然你明确地排除了这个选项,一个惯用的解决方案是不可能的。编程是重用,而不是重新创造。当然,如果这是一个现实世界的问题,你绝对是正确的。但是考虑一下所有的Haskell书,为了学习的目的,序曲功能正在被重新实施。你不同意吗?有些解决方案比其他解决方案更惯用吗?是的,编程是关于重用的,但学习有时可能是关于重新发明。