Get the subtrees of an ast - functional-programming

I have a boolean abstract syntax tree
type bast =
True
| False
| Not of bast
| Or of bast * bast
| And of bast * bast
and I want to apply on it a function and get all the subtrees that return true for this function.
My try:
let findtrees f (ast: bast ) =
let rec findtree (tree: bast ) (mylist: bast list) = match tree with
| True ->
if (f tree)=true then mylist#[tree] else []
| False ->
if (f tree)=true then mylist#[tree] else []
| Not e -> Not (findtree e subtrees)
| And (e1,e2) -> And (findtree e1 mylist, findtree e2 mylist)
| Or (e1,e2) -> Or (findtree e1 mylist, findtree e2 mylist)
in findtree ast []
I get an error:
Error: The variant type list has no constructor Not
Tried also with this:
let findtrees f (ast: bast) =
let rec findtree (tree: bast) (mylist: bast list) = match tree with
(True|False) -> mylist
| subtree ->
if (f subtree)=true then
mylist#[subtree]
else
select_tree subtree mylist
in findtree ast []
Compiles fine but never terminates!

first of all, it shouldn't compile, since Bast should be lowercased.
That is because you return a value of type list on first two cases, and an atom on a latter three. Moreover, (compiler didn't mentioned it yet, but will soon) Not constructor accepts a bast, but you're trying to create it with a bast list

Here's what I would probably write as a first working attempt:
let findtrees f (ast: bast ) =
let rec findtree tree mylist =
let mylist = if f tree then tree::mylist else mylist in
match tree with
| True| False -> mylist
| Not e -> findtree e mylist
| Or (e1,e2)
| And (e1,e2) -> findtree e2 ## findtree e1 mylist
in findtree ast []
Some remarks:
You don't need to write exp = true for any expression exp (in your case it was f tree), since it implies that that exp is of type boolean and the resulting value would be exactly the same (please write the truth table to verify that)
I replaced mylist#[tree] with tree::mylist which is faster, but will produce a list in reverse order. If you care about that order, and wish to have the latest tested tree at the end of the list, simply apply List.rev to the result (you may of course include that in the body of findtrees)
Because your tree represents boolean expressions, there's perhaps a better way of handling the problem you are trying to solve.

Related

A function that compare a two lists of string

I am a new at F# and i try to do this task:
Make a function compare : string list -> string list -> int that takes two string lists and returns: -1, 0 or 1
Please help. I spend a lot of time, and i can not understand how to implement this task.
Given the task I assume what your professor wants to teach you with this exercise. I'll try to give you a starting point without
Confusing you
Presenting a 'done-deal' solution
I assume the goal of this task is to work with recursive functions and pattern matching to element-wise compare their elements. It could looks somewhat like this here
open System
let aList = [ "Apple"; "Banana"; "Coconut" ]
let bList = [ "Apple"; "Banana"; "Coconut" ]
let cList = [ "Apple"; "Zebra" ]
let rec doSomething f (a : string list) (b : string list) =
match (a, b) with
| ([], []) ->
printfn "Both are empty"
| (x::xs, []) ->
printfn "A has elements (we can unpack the first element as x and the rest as xs) and B is empty"
| ([], x::xs) ->
printfn "A is empty and B has elements (we can unpack the first element as x and the rest as xs)"
| (x::xs, y::ys) ->
f x y
printfn "Both A and B have elements. We can unpack them as the first elements x and y and their respective tails xs and ys"
doSomething f xs ys
let isItTheSame (a : string) (b : string) =
if String.Equals(a, b) then
printfn "%s is equals to %s" a b
else
printfn "%s is not equals to %s" a b
doSomething isItTheSame aList bList
doSomething isItTheSame aList cList
The example has three different lists, two of them being equal and one of them being different. The doSomething function takes a function (string -> string -> unit) and two lists of strings.
Within the function you see a pattern match as well as a recursive call of doSomething in the last match block. The signatures aren't exactly what you need and you might want to think about how to change the parametrization for cases where you don't want to stop the recursion (the last match block - if the strings are equal you want to keep on comparing, right?).
Just take the code and try it out in FSI. I'm confident, that you'll find the solution 🙂
In F# many collections are comparable if their element type is:
let s1 = [ "a"; "b" ]
let s2 = [ "foo"; "bar" ]
compare s1 s2 // -5
let f1 = [ (fun () -> 1); fun () -> 2 ]
let f2 = [ (fun () -> 3); fun () -> 42 ]
// compare f1 f2 (* error FS0001: The type '(unit -> int)' does not support the 'comparison' constraint. *)
so
let slcomp (s1 : string list) s2 = compare s1 s2 |> sign
Posting for reference as the original question is answered already.

What does the h :: t pattern matching means in OCaml?

I'm reading https://ocaml.org/learn/tutorials/99problems.html and it has 2 examples:
# let rec last_two = function
| [] | [_] -> None
| [x;y] -> Some (x,y)
| _::t -> last_two t;;
I understand the first one: _::t means pattern match anything and call it t
But at
# let rec at k = function
| [] -> None
| h :: t -> if k = 1 then Some h else at (k-1) t;;
I don't understand what h means. For me it should be _:: t -> ... to match anything and call it t
The pattern _ :: t doesn't mean what you say. It matches any non-empty list and calls the tail of the list t.
The pattern h :: t matches any non-empty list, calls the head of the list h (one element, the first one), and the tail of the list t (zero or more elements after the first one).
The operator :: is the list constructor (often called "cons"), which is why these patterns match lists.
Here are examples of :: as list constructor:
# true :: [];;
- : bool list = [true]
# 1 :: [2; 3];;
- : int list = [1; 2; 3]
As is usual in OCaml, the pattern for a list uses the same syntax as the constructor.
# match [1;2;3] with [] -> None | h :: t -> Some (h, t);;
- : (int * int list) option = Some (1, [2; 3])
The h::t pattern matches the head and tail of the list to the variables h and t.
So if I pattern match like this:
match [1; 2; 3] with
| h::t -> (* Some code... *)
h will have a value of 1, and t will have the value of [2; 3].
:: is a constructor. Pattern matching in this fashion pattern matches against constructors. They create a new datatype out of two values. :: is a constructor, and its type, list, is recursive. Here's a sample definition of the list type:
type 'a list =
| []
| (::) 'a * ('a list)
;;
So the list type is recursive because its constructor, ::, calls itself.
Honestly, I could write half a book on lists. They're the bread and butter of functional programming languages.
If you're wondering why you can't pattern match on operators, this is why. You can't pattern match on operators, only constructors.
Yes, indeed when you type in a function let's take for example this one:
let is_empty (l: int list) : int =
begin match l with
| [] -> 1
| h::t -> 0
end;;
Therefore, in this function that tests if a list is empty or not, if [], an empty list it returns one or in boolean true but if h::t, meaning that there is one or more value, the function returns 0, meaning it's false.

F# adding lists

How would I go about adding sub-lists.
For example, [ [10;2;10]; [10;50;10]] ----> [20;52;20] that is 10+10, 2+50 and 10+10. Not sure how to start this.
Fold is a higher order function:
let input = [[10;2;10]; [10;50;10]]
input |> Seq.fold (fun acc elem -> acc + (List.nth elem 1)) 0
val it : int = 52
Solution 1: Recursive version
We need a helper function to add two lists by summing elements one-to-one. It is recursive and assumes that both lists are of the same length:
let rec sum2Lists (l1:List<int>) (l2:List<int>) =
match (l1,l2) with
| ([],[]) -> []
| (x1::t1, x2::t2) -> (x1+x2)::sum2Lists t1 t2
Then the following recursive function can process a list of lists, using our helper function :
let rec sumLists xs =
match xs with
| [] -> [] // empty list
| x1::[] -> x1 // a single sublist
| xh::xt -> sum2Lists xh (sumLists xt) // add the head to recursion on tail
let myres = sumLists mylist
Solution 2: higher order function
Our helper function can be simplified, using List.map2:
let sum2hfLists (l1:List<int>) (l2:List<int>) = List.map2 (+) l1 l2
We can then use List.fold to create an on the flow accumulator using our helper function:
let sumhfList (l:List<List<int>>) =
match l with
| [] -> [] // empty list of sublist
| h::[] -> h // list with a single sublist
| h::t -> List.fold (fun a x -> sum2hfLists a x) h t
The last match case is applied only for lists of at least two sublists. The trick is to take the first sublist as starting point of the accumulator, and let fold execute on the rest of the list.

Converting a binary tree to a list using fold function in Ocaml

Given:
type 'a tree = Empty | Node of 'a * 'a tree * 'a tree
Use:
let rec tree_fold f e t = match t with
| Empty -> e
| Node (x, l, r) -> f x (tree_fold f e l) (tree_fold f e r);;
to convert a binary tree to a list.
Example.
let someTree = Node (1,Node(2,Node(3,Empty,Empty),Empty),Empty)
tree2list someTree gives [1;2;3].
My attempt:
let tree2list tr = match tr with
| Empty -> Empty
| Node (x,l,r) -> (tree_fold (fun acc tree-> tree::acc) [] tr)
It gives the error:
This expression has type 'a list but an expression was expected of type 'b -> 'b .
I've been at this for hours and keep getting similar errors. Any help would be very appreciated, even just a small hint would be great.
Thanks.
function that you should pass to a tree_fold accepts three arguments, and you're passing a function that can take only two arguments. That's what compiler tries to say. Of course, ther're some other problems, but I hope tha you'll cope with them!

Convert tree to list

How can I convert a tree to a list:
So far I have the following code but its giving several issues:
type 'a tree = Lf | Br of 'a * 'a tree * 'a tree;;
let rec elementRight xs = function
| LF ->false
| Br(m,t1,t2) -> if elementRight xs t1 = false then t1::xs else element xs t1;; //cannot find element
let rec elementLeft xs = function
| LF ->false
| Br(m,t1,t2) -> if elementLeft xs t2 = false then t2::xs else element xs t2 ;; //cannot find element
let rec element xs = function
| LF ->[]
| Br(m,t1,t2) -> xs::(elementRight xs t1)::(elementRight xs t2)::(elementLeft xs t1)::(elementLeft xs t2);;
There are a number of problems with your code:
You shouldn't have ;; at the end of lines (I'm guessing this means you're copy and pasting into the repl, you should really use an fsx file instead and use "send to repl").
This: | LF ->false is returning a bool, while this: | Br(m,t1,t2) -> if elementRight xs t1 = false then t1::xs else element xs t1 is returning an 'a list. An expression can only have one type, so returning two is a compile error. I'm guessing what you really are meaning to do is have the leaf return [] and then check for empty list in your branch case something like this:
let rec elementRight xs = function
| LF ->[]
| Br(m,t1,t2) -> if elementRight xs t1 = List.empty then t1::xs else element xs t1
3 . when using mutually recursive functions you need to use the and keyword for all declarations but the first like this:
let rec elementRight xs = function
...
and elementLeft xs = function
...
and element xs = function
...

Resources