首页 > 解决方案 > ocaml 类型的初学者

问题描述

这可能是一个简单的问题,但我不确定为什么会出现此错误:

我在文件中定义了一个类型

type tree = TreeNode of string * tree list;;

我在另一个[编辑添加的getFt和getSt函数]中有这个函数定义

let getFt input = match input with
                    | (x, y) -> x;;

let getSt input = match input with
                        | (x, y) -> y;;
let rec traverse input = 
            match (getFt(input)) with
            | "S" -> nodeS (getSt(input))
            | "T" -> nodeT (getSt(input))
    and traverseList input =
            match (getFt(List.hd(input))) with
            | "S" -> nodeS (List.tl(input))
            | "T" -> nodeT (List.tl(input))
    and nodeS input =
            match (getFt(List.hd(input))) with
            | "TRUE" -> (TreeNode("TRUE", []))
            | "FALSE" -> (TreeNode("FALSE", []))
            | "(" -> (traverseList (List.tl(input)))
            | x -> (TreeNode(x, []))
    and nodeT input =
            match (getFt(List.hd(input))) with
            | "not" -> (TreeNode("not", [(nodeS (List.tl(input)))]))
            | "and" -> (TreeNode("and", [(traverseList (List.tl(input)) )]))
            | "or" ->  (TreeNode("or", []));;

let buildAbstractSyntaxTree (input : tree) : tree = traverse input;;

并且每当我编译时都会收到此错误:[编辑我输入了错误的错误]

Error: This expression has type Proj2_types.tree
   but an expression was expected of type string * (string * 'a) list

标签: ocaml

解决方案


这个答案不是为了取代 Jeffrey 的答案,而是为了给你一些关于你进一步 OCaml 代码的提示。

TL; DR:字符串是“坏的”

如果我正确阅读了您的代码,则您的树是一对包装的树Treenode of string * tree list(它看起来并不像一棵树,而更像是一条路径,因为您没有左分支和右分支,因此您有一个节点后跟什么都没有或另一个节点等。实际上你刚刚定义了一个列表;-))

你开始匹配它从traverse.

traverse看看这对的第一部分是字符串"S"还是字符串"T",所以让我们重写它:

let rec traverse = function
  | Treenode ("S", t) -> nodeS t
  | Treenode ("T", t) -> nodeT t

做什么nodeS?它匹配列表头部的第一部分,并检查它是否为、"TRUE"或其他任何内容。如果它是前两个,它只是创建一个 new ,它是遍历剩余列表的括号,如果它是其他任何东西,它只是用它创建一个 new 。因此,您有 3 个案例做完全相同的事情,但您为每个案例做了一个案例。让我们重写它:"FALSE""("TreeNodeTreeNode

and nodeS = function
  | [] -> failwith "TODO"
  | ("(", _) :: tl -> traverseList tl
  | (x, _) :: _ -> TreeNode (x, [])

至于nodeT,我们要么期望找到"and""or"要么"not"给出:

and nodeT = function
  | [] -> failwith "TODO"
  | ("not", _) :: tl -> TreeNode("not", [nodeS tl])
  | ("and", _) :: tl -> TreeNode("and", [traverseList tl])
  | ("or", _) :: tl -> TreeNode("or", [])

最后,traverseList:

and traverseList = function
  | [] -> failwith "TODO"
  | ("S", _) :: tl -> nodeS tl
  | ("T", _) :: tl -> nodeT tl

问题出现。首先,您不处理空列表(我的 `failwith "TODO"),但最重要的是,您操作字符串,如果您将“A”作为第一个字符串会发生什么?从你如何构建你的树可能是不可能的,但它没有按类型显示。这就是 sum 类型可以帮助您的地方。尝试像这样重新定义你的树:

type node = S | T | True | False | Par | Not | And | Or 
type tree = TreeNode of node * tree list

看看它会把你引向何方。OCaml 强烈强调由类型引导的风格。字符串对文本有用,但对类型有用(想象一下,如果你开始在 AST 中添加自定义函数,你会匹配“myfun of int -> int -> string”吗?听起来很乏味,你不同意吗?)

我希望你能阅读我的代码(和 Jeffrey 的代码)并发现 OCaml 中的模式匹配是多么强大,这意味着你不必使用你的getFtgetSt函数。如果您有任何问题,请随时发表评论,这里的人很乐意提供帮助;-)


推荐阅读