Home > Software design >  How to pass a type/tree in a function
How to pass a type/tree in a function

Time:11-24

I have these defined types

   type Name = string
   type Flow = int
   type River = R of Name * Flow * River list
   type Tributaries = River list

And i want to declare a function contains n r that returns a boolean value if n is contained in River or any of it's branches/Tributaries. and i've came up with this so far

let rec contains (n:Name)(r:River) =
    match r with
        |R(Name,_,_) when Name = n -> true 
        |R(_,_,Tr) -> contains n Tr
        |_ -> false

However F# cant recoginze Tr as Tr is a list and not of type river so i can't pass it in of course, how can i do this in a nice and clean way without declaring two seperate functions to help?

CodePudding user response:

Gus's answer fixes the specific issue and answers the question, but often things like this are slightly more elegant if work on a list of rivers (a 'forest' of trees) rather than a single one.

The solution is a little odd because the recursive step creates a new river to search in based on the tail of the tributaries of the input river, perfectly valid, but if feels a little odd.

first lets tidy up the types

type Name = string
type Flow = int
type Tributaries = River list
and River = R of Name * Flow * Tributaries

now we write something that feels harder than what you want to do, but is in fact (to me) intuitively easier to understand, i.e. you check the tail of the passed list AND you check the tributaries into the current river.

let rec containsTributaries (n: Name) (rs: River list) =
    match rs with
    | R (name, _, _) :: _ when name = n -> true
    | R (_, _, tribs) :: tail -> containsTributaries n tail || containsTributaries n tribs
    | _ -> false

then searching for a single river is trivial

let rec contains (n: Name) (river: River) =
    containsTributaries n [ river ]

(but basically this is the same answer as Gus's)

CodePudding user response:

The problem is Tr is a list and your function expect a River structure.

So, you would have to decompose the list in head and tail and check on both.

You can do that by changing the second match:

|R(_,_,Tr) -> contains n Tr

to

| R (name, f, x::xs) -> contains n x || contains n (R (name, f, xs))

Of course there are more efficient ways of doing this and you can use built in functions, but if you're learning this is the solution you want to come up in first place.

  • Related