OCaml 此变体表达式预计具有单位类型

问题描述 投票:0回答:3

我无法弄清楚 if 语句有问题。
我的代码:

type chess_board = char array array;;
type position = int * int;;

let chess_board_1:chess_board = [|
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';'Q';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    |];;
    
let queen_targeting (chess:chess_board) pos =
    match pos with
    |(x0, y0) ->
        for y = 0 to Array.length chess -1 do
            for x = 0 to Array.length chess.(y) -1 do
                if chess.(y).(x) = 'Q' 
                then
                    if (
                        x = x0 ||         (* Check horizontaly *)
                        y = y0 ||         (* Check verticaly *)
                        x - x0 = y - y0   (* Check diagonaly *)
                    ) 
                    then true
                    else false
            done
        done
;;

queen_targeting chess_board_1 (3, 3);; (* Expected true *)

我收到此错误消息:

File "[32]", line 27, characters 25-29:
Error: This variant expression is expected to have type unit
       The constructor true does not belong to type unit
Characters 874-878:
                      then true

我不知道这意味着什么。我测试了 if 语句在其他方法中返回 true/false,效果很好。我不知道为什么它在这种情况下不起作用,所以如果有人可以提供帮助,请这样做。

if-statement compiler-errors ocaml
3个回答
3
投票

更实用的解决方案是使用

Array.iteri
:

let queen_targeting (chess:chess_board) (x0,y0) =
  let exception Return of bool in
  let threat y x case =
    if case = 'Q' && (x = x0 || y = y0 || x - x0 = y - y0) then
      raise (Return true)
  in
  match Array.iteri (fun y -> Array.iteri (threat y)) chess with
  | () -> false
  | exception Return b -> b

这里的异常用于当我们发现女王瞄准该位置时立即返回。


1
投票

“for 表达式”必须返回

unit
,因此结果不会传播。例如:

# let x = for y = 0 to 10 do true done;;

潜在客户发出此警告:

Warning 10: this expression should have type unit.
val x : unit = ()

解决方案是使用可变引用:

type chess_board = char array array;;
type position = int * int;;

let chess_board_1:chess_board = [|
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';'Q';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    |];;
    
let queen_targeting (chess:chess_board) pos =
    match pos with
    |(x0, y0) ->
        let result = ref false in
        for y = 0 to Array.length chess -1 do
            for x = 0 to Array.length chess.(y) -1 do
                if chess.(y).(x) = 'Q' 
                then
                    if (
                        x = x0 ||         (* Check horizontaly *)
                        y = y0 ||         (* Check verticaly *)
                        x - x0 = y - y0   (* Check diagonaly *)
                    ) 
                    then result := true
                    else result := false
            done
        done;
        false || !result

;;

queen_targeting chess_board_1 (3, 3);;

0
投票

其他答案已经解决了您迫在眉睫的问题,但是有一些机会可以解决代码中不适合发表评论的问题。希望这些建议能够消除无关的噪音,让您将来更容易推理代码。

这听起来有些迂腐,但请记住 OCaml 中没有条件语句。相反,它们是具有值的表达式。我怀疑您已经明白这一点,但术语很重要。

此外,条件语句的使用方式也存在一些问题。如果您唯一要做的就是返回 true 或 false,那么只需直接使用布尔表达式即可。考虑一个简单的例子。

if a < b && b < c then true else false

这与:

没有什么不同
a < b && b < c

第三,当您有嵌套条件时,通常可以简化它们。我将稍微修改一下您的代码并暂时删除注释。

if chess.(y).(x) = 'Q' then
  if x = x0 || y = y0 || x - x0 = y - y0 then 
    true
  else 
    false

我们知道我们可以将其简化为:

if chess.(y).(x) = 'Q' then
  x = x0 || y = y0 || x - x0 = y - y0 

但是,如果第一个条件满足,我们只会检查

||
ed 条件,因此我们可以将整个事情重写为:

chess.(y).(x) = 'Q' && (x = x0 || y = y0 || x - x0 = y - y0) 

这可以在@octachron发布的答案中看到(但没有详细说明)。

另请注意,您实际上已经接近拥有一个不需要

;;
令牌的格式良好的 OCaml 程序了。最后一个表达式只需是顶级绑定即可。

type chess_board = char array array
type position = int * int

let chess_board_1:chess_board = [|
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    [|' ';' ';' ';' ';' ';' ';'Q';' '|];
    [|' ';' ';' ';' ';' ';' ';' ';' '|];
    |]
    
let queen_targeting (chess:chess_board) pos =
    match pos with
    |(x0, y0) ->
        for y = 0 to Array.length chess -1 do
            for x = 0 to Array.length chess.(y) -1 do
                if chess.(y).(x) = 'Q' 
                then
                    if (
                        x = x0 ||         (* Check horizontaly *)
                        y = y0 ||         (* Check verticaly *)
                        x - x0 = y - y0   (* Check diagonaly *)
                    ) 
                    then true
                    else false
            done
        done

let () =
  queen_targeting chess_board_1 (3, 3) (* Expected true *)
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.