Ocaml 类型不匹配?预期单位,但为已定义类型

Posted

技术标签:

【中文标题】Ocaml 类型不匹配?预期单位,但为已定义类型【英文标题】:Ocaml Type Mismatch? Expected Unit but is a defined type 【发布时间】:2021-07-20 13:11:36 【问题描述】:

我收到以下错误,但我无法弄清楚为什么会这样。任何帮助表示赞赏。该程序是 Ocaml 中的解释器。 tryOcaml 下划线的那段代码是代码的最后一位“处理器令牌[];”不知道为什么会是类型不匹配或不匹配在代码中发生的位置。

错误:此表达式的类型为 stackValue list 但是需要一个单位类型的表达式

type stackValue = NUM of int | BOOL of bool | ERROR | STRING of string | NAME of string | UNIT

type com = PUSH of stackValue | POP | ADD | SUB | MUL | DIV | REM | NEG | SWAP | QUIT | TOSTRING | PRINTLN (*| CAT | AND | OR | NOT | LESSTHAN | EQUAL | IF | BIND let com com end | funBind com com [return] funEnd | call*)

let interpreter ( (inFile : string), (outFile : string )) : unit = 
let ic = open_in inFile 
in
let oc = open_out outFile 
in

let rec loop_read acc =
  try 
      let l = String.trim(input_line ic) in loop_read (l::acc)
  with
  | End_of_file -> List.rev acc 
  in

  let ls_str = loop_read [] 
  in
let checkrest s = 
  match s.[0] with
  | '"' ->  if s.[(String.length s) -1]='"' then STRING(String.sub s 1 ((String.length s)-2)) else ERROR
  | '-' | '0'..'9' -> (try NUM(int_of_string s) with _ ->ERROR)
  | '_' | 'a'..'z' | 'A'..'Z' -> NAME(s)
  |_ -> ERROR
  in

  let str2sv s =
    match s with
    |":true:" -> BOOL(true)
    |":false:" -> BOOL(false)
    |":unit:" -> UNIT
    |":error:" -> ERROR
    |_-> checkrest s 
    in

  let str2com s = 
    match s with 
    |"quit" -> QUIT
    |"add" -> ADD
    |"sub" -> SUB
    |"mul" -> MUL
    |"div" -> DIV
    |"rem" -> REM
    |"pop" -> POP
    |"neg" -> NEG
    |"swap" -> SWAP
    (*|"cat" -> CAT
    |"and" -> AND
    |"or" -> OR
    |"not" -> NOT
    |"lessthan" -> LESSTHAN
    |"equal" -> EQUAL
    |"if" -> IF
    |"bind" -> BIND*)
    |"toString" -> TOSTRING
    |_ -> if String.sub s 0 4 = "push" then let x = str2sv (String.sub s 5 ((String.length s) -5)) in PUSH(x) else PUSH(ERROR)
    in

let tokens = List.map str2com ls_str
in

let sv2str sv =
  match sv with
  |BOOL(true) -> STRING(":true:")
  |BOOL(false) -> STRING(":false:")
  |UNIT -> STRING(":unit:")
  |ERROR -> STRING(":error:")
  |STRING(s) -> STRING(s)
  |NAME(s) -> STRING(s)
  |NUM(x) -> STRING(string_of_int(x))
in

let file_write value = Printf.fprintf oc "%s\n" value 
in

let rec processor comlist stack =
  match (comlist,stack) with
  |(PUSH(x)::comst, stack) -> processor comst (x::stack)
  |(POP::comst, stackValue::reststack) -> processor comst reststack
  |(POP::comst, []) -> processor comst (ERROR::stack)
  |(ADD::comst, NUM(a)::NUM(b)::reststack) -> processor comst (NUM(a+b)::reststack)
  |(ADD::comst, stack) -> processor comst (ERROR::stack)
  |(SUB::comst, NUM(a)::NUM(b)::reststack) -> processor comst (NUM(b-a)::reststack)
  |(SUB::comst, stack) -> processor comst (ERROR::stack)
  |(MUL::comst, NUM(a)::NUM(b)::reststack) -> processor comst (NUM(a*b)::reststack)
  |(MUL::comst, stack) -> processor comst (ERROR::stack)
  |(DIV::comst, NUM(a)::NUM(b)::reststack) -> if (NUM(a)=NUM(0)) then (processor comst (ERROR::NUM(a)::NUM(b)::reststack)) else (processor comst (NUM(b/a)::reststack))
  |(DIV::comst, stack) -> processor comst (ERROR::stack)
  |(REM::comst, NUM(a)::NUM(b)::reststack) -> if (NUM(a)=NUM(0)) then (processor comst (ERROR::NUM(a)::NUM(b)::reststack)) else (processor comst (NUM(b mod a)::reststack))
  |(REM::comst, stack) -> processor comst (ERROR::stack)
  |(NEG::comst, NUM(a)::reststack) -> processor comst (NUM(-a)::reststack)
  |(NEG::comst, stack) -> processor comst (ERROR::stack)
  |(SWAP::comst, x::xs::reststack) -> processor comst (xs::x::reststack)
  |(SWAP::comst, stack) -> processor comst (ERROR::stack)
  |(TOSTRING::comst, x::reststack) -> let s = sv2str x in processor comst (s::reststack)
  |(TOSTRING::comst, []) -> processor comst (ERROR::stack)
  |(PRINTLN::comst, x::reststack) -> (match x with 
                                        |STRING(x) -> file_write x; processor comst reststack
                                        |_ -> ERROR::stack)
  |(PRINTLN::comst, []) -> processor comst (ERROR::stack)
  |(QUIT::comst, stack) -> []
  |(_,_) -> []

in
processor tokens [];;

【问题讨论】:

具体有什么不明白的?您指定interpreter 函数应返回unit,但其中的最后一个表达式是对返回stackValue listprocessor 函数的调用。因此类型不匹配。 我猜如何返回一个单位?不知道如何返回一个单元,我真的不需要这个单元来做任何事情,因为这个程序的功能就像一个 void 函数并处理处理器内部的所有事情。我对 Ocaml 很陌生,这种功能不是我的强项。 【参考方案1】:

让我最小化你的代码来突出问题,

let interpreter ( (inFile : string), (outFile : string )) : unit = 
  ... <snip> ...
let rec processor comlist stack =
  match (comlist,stack) with
  |(PUSH(x)::comst, stack) -> processor comst (x::stack)
  |(QUIT::comst, stack) -> []
  ... <snip> ...
  |(_,_) -> []

in
processor tokens []

花点时间仔细看看上面的sn-p,你看出问题了吗?如果还没有,请回答以下问题:

    processor 函数返回什么类型的值? interpreter 应该返回什么类型的值?

例如,考虑processor [] [],它将返回[],因此我们可以看到processor tokens []_ list 类型的值,但是您有一个注释: unit 表示您的interpreter input output 将评估到 unit 类型的值,而不是计算为堆栈。

如果你真的不需要堆栈,你可以忽略它,

ignore (processor tokens [])

其中ignore是一个简单的函数,大致有以下实现,

let ignore x = ()

也就是说,它只是忽略了它的参数,因此它的类型为'a -&gt; unit。不用ignore你也可以写,

let _stack = processor tokens [] in
()

因此您忽略返回的堆栈(惯例是在忽略值前面加上下划线前缀)并返回 () 值而不是 _stack

【讨论】:

那么忽略只是执行函数然后丢弃括号内函数的返回值吗?我把它放进去,那个错误就消失了,但我还有另一个错误。 “错误:非法字符(\r)”我昨晚看到了这个,但我不知道我做了什么来修复它。对忽略有很大帮助,从来不知道这是一件事 是的,ignore 计算其表达式,然后基本上丢弃结果。如果你还没有弄清楚你的新问题,你应该打开一个新问题。仅从错误消息中无法判断发生了什么。一般来说,在源代码中包含'\r'(回车) 并不违法。所以上下文很重要。 你可能会这样想,但它只是一个函数。 OCaml 是一种急切的语言,每次编写函数应用程序时,例如 print_int 42 都会立即执行,无论它是传递给另一个函数还是被忽略。基本上,OCaml 机制(或学者演讲中的语义)是执行所有功能应用程序,直到什么都不剩 :) 我已经用更多细节更新了答案。

以上是关于Ocaml 类型不匹配?预期单位,但为已定义类型的主要内容,如果未能解决你的问题,请参考以下文章

元组中的 OCaml 意外类型不匹配

Ocaml 值与模块和签名中的参数化类型不匹配

Ocaml 类型中的 Int 的 Int

Spring Data JPA 'jpaMappingContext' 错误,IllegalStateException:预期能够解析类型但为空

ocaml 中的匹配是不是调用构造函数?

在 Pytorch F.nll_loss() 中预期的类型为 torch.LongTensor 的对象,但为参数 #2 'target' 找到了类型 torch.FloatTensor