简体   繁体   中英

OCaml This variant expression is expected to have type unit

I'm having a problem with if statements that I cannot figure out.
My code:

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 *)

I get this ERROR message:

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

I have no clue what this means. I tested if statements returning true/false in other methods and it worked just fine. I don't know why it wouldn't work in this scenario so if anyone can help please do.

A more functional solution would be to use 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

Here the exception is used for returning as soon that we find a queen targeting the position.

A "for expression" must return unit , so the result is not propagated. For example:

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

leads emit this warning:

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

A solution would be to use a mutable reference:

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);;

The other answers have addressed your immediate question, but there are some opportunities to address issues in your code that aren't well-suited to a comment. Hopefully these suggestions will make it easier to reason about your code in the future by eliminating extraneous noise.

It will sound pedantic, but try to remember that there are no conditional statements in OCaml. Rather they are expressions which have a value. I suspect you understand this already, but terminology is important.

Additionally, there are some issues with how you're using conditionals. If the only thing you're doing is returning true or false, then just use the boolean expression directly. Consider a simple example.

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

This is no different than:

a < b && b < c

Thirdly, when you have nested conditionals, these can often be simplified. I'm going to reform your code a little bit and remove the comments for now.

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

We know we can simplify this into:

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

But we'll only check for the || ed conditions if the first condition checks out, so we can rewrite this whole thing as:

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

This can be seen (but not elaborated on) in the answer @octachron posted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM