0
votes

I have a recursive function that creates a tree like so:

let rec evaluate node = 
    let neighbors = getNeighbors node
    let visited = [for x, y in neighbors do
                       if not tiles.[y].[x] then
                           tiles.[y].[x] <- true
                           evaluate (x, y)]
    if List.length visited > 0 then 
        Node(x, y, visited) 
    else 
        Leaf(x, y)

Node and Leaf come from this definition:

type Tree =
    | Leaf of int * int
    | Node of int * int * Tree list

and tiles is a 2-dimensional array of booleans representing which tiles have been visited (I'm implementing maze generation).

Now the above function does not compile. The inferred type is int*int -> unit, when it should be int*int -> Tree.

I attempted to force the return type to be Tree, but then the compiler complains that the call to evaluate should have type unit but has type Tree.

I have found a workaround using a sequence expression and converting to list:

let visited = Seq.toList (seq { 
                for x, y in neighbors do
                    if not tiles.[y].[x] then
                        tiles.[y].[x] <- true
                        yield evaluate (x, y)})

But I don't understand why using a list expression doesn't work.

2

2 Answers

1
votes

I was just missing a yield keyword:

let visited = [for x, y in neighbors do
                   if not tiles.[y].[x] then
                       tiles.[y].[x] <- true
                       yield evaluate (x, y)]

This compiles and doesn't require forcing the return type.

0
votes

For the list expression you need to replace do with -> - see here http://msdn.microsoft.com/en-us/library/dd233224.aspx

Also, in that case the right hand side must have a consistent type. I would change it to

[for x, y in (neighbors |> List.filter (fun (x2,y2) -> not tiles.[y2].[x2])) -> ...