F# 解析器组合器

4
我将尝试翻译有关单子解析器的示例(https://www.cs.nott.ac.uk/~gmh/pearl.pdf)到F#。
到目前为止,我已经完成了:
type Parser<'a> = Parser of  (string -> ('a*string) list)

let item : Parser<char> =
  Parser (fun (s:string) -> 
                match s with
                | "" -> []
                | null -> []
                | _ -> (s.Chars(0),s.Substring 1)::[])

let sat (pred : (char -> bool)) : Parser<char> =
  parserWf
    {
       let! c = item
       if pred c then return c
    }

let char c : Parser<char> =
  sat (fun c' -> c'.Equals(c))

let rec string (str:string) : Parser<string> =
  parserWf
    {
        if (str.Length > 0)
        then
            let! c = char (str.Chars 0)
            let! cs = string (str.Substring 1)
            printfn "String: %s" cs
            return c.ToString() + cs
        else
            return ""
    }

如果我从 string 方法中删除 else return "" ,那么结果总是空列表。 在 Haskell 中,字符串函数的声明如下:

string :: String -> Parser String
string "" = return ""
string (c:cs) = do {char c; string cs; return (c:cs)}  

这个可以正常工作。 为什么F#函数不能按预期工作?


4
你应该扩展“不起作用”的定义。是类型错误?运行时错误?还是结果错误? - chi
F#函数为什么在去掉else return ""后不能按预期工作?这要取决于您的预期。也许您应该说出您所期望的是什么。 - Daniel Wagner
如果我删除字符串函数的最后两行(否则返回“”),然后在F#中执行'runParser(string“hello”)“hello!”时,我得到了空列表,但在Haskell中我得到了[(“hello”,“!”)]。 - user3535953
1个回答

0

我的Haskell有点生疏,但是你发布的代码片段不是等同于你的F#代码吗?也就是说,在Haskell中,你需要递归的基本情况(空字符串)?

如果你删除else部分,倒数第二个调用string的函数(即只剩一个字符的那个)将无法从其递归调用(传递“”)中获得结果,因此它也将返回无效结果。这会向上传播,最终你会得到一个空列表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接