Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added higher order functions documentation to tutorials and exercises folders #2

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions exercises/exercisesforhof/answers.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

(* 1. `filter_map` function: *)
let filter_map f l =
List.fold_right
(fun x acc ->
match f x with
| Some y -> y :: acc
| None -> acc)
l []

(* This function uses `fold_right` to iterate through the list `l` from right to left, and applies the function `f` to each element. If `f` returns a `Some` value, it is appended to the result list, otherwise it is skipped. *)

(* 2. `compose` function: *)


let compose f g x = f (g x)


(* This function takes two functions `f` and `g`, and returns a new function that applies `g` to its argument, and then applies `f` to the result. *)

(* 3. `exists` function: *)


let exists p l =
List.fold_left
(fun acc x -> acc || p x)
false l


(* This function uses `fold_left` to iterate through the list `l` from left to right, and applies the predicate function `p` to each element. If `p` returns `true` for any element, the function returns `true`, otherwise it returns `false`. *)

(* 4. `iter2` function: *)


let iter2 f l1 l2 =
List.iter2 f l1 l2


(* This function uses the built-in `iter2` function from the `List` module, which iterates through two lists `l1` and `l2` in parallel, applying the function `f` to the corresponding elements of each list. *)

(* 5. `flatten` function: *)


let flatten l =
List.fold_left
(fun acc x -> acc @ x)
[] l


(* This function uses `fold_left` to iterate through the list `l` from left to right, and appends each sub-list to the accumulator list. The resulting list is flattened, with all the elements of the sub-lists combined into a single list. Note that this implementation is not very efficient, as it performs many list concatenations, which can be slow for large lists. *)
12 changes: 12 additions & 0 deletions exercises/exercisesforhof/questions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Questions:
These are a few questions that you can solve using higher-order functions in OCaml:

1. Write a function `filter_map` that takes a list `l` and a function `f` that returns an optional value, and returns a new list containing only the non-`None` values returned by `f`.

2. Write a function `compose` that takes two functions `f` and `g` and returns a new function that applies `f` to the result of applying `g` to its argument.

3. Write a function `exists` that takes a list `l` and a predicate function `p`, and returns `true` if there exists an element in `l` for which `p` returns `true`, and `false` otherwise.

4. Write a function `iter2` that takes two lists `l1` and `l2` and a function `f`, and applies `f` to the corresponding elements of `l1` and `l2`. The function `f` takes two arguments, one from `l1` and one from `l2`.

5. Write a function `flatten` that takes a list of lists `l` and returns a flattened list containing all the elements of the sub-lists.
87 changes: 87 additions & 0 deletions tutorials/basic-highorderfunctions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
Higher-order functions

-----------------------------------------------------------------------------------------------------------------------------------------

Higher-order functions are functions that take other functions as arguments or return functions as their results. Here is an example of a higher-order function that takes a function `f` and applies it to each element of a list `l`:


let rec map f l =
match l with
| [] -> []
| x :: xs -> f x :: map f xs


The `map` function takes a function `f` as its first argument and a list `l` as its second argument. It applies `f` to each element of `l` and returns a new list containing the results. For example, if we define a function `square` that squares its argument:


let square x = x * x


We can use `map` to apply `square` to each element of a list:


let l = [1; 2; 3]
let l_squared = map square l (* returns [1; 4; 9] *)

-----------------------------------------------------------------------------------------------------------------------------------------

Another example of a higher-order function in OCaml is the `fold_left` function, which takes a function `f`, an initial accumulator value `acc`, and a list `l`, and applies `f` to each element of `l` and the current accumulator value to produce a new accumulator value. Here's an example implementation of `fold_left`:


let rec fold_left f acc l =
match l with
| [] -> acc
| x :: xs -> fold_left f (f acc x) xs


We can use `fold_left` to compute the sum of a list of integers:


let sum l = fold_left (+) 0 l


The `sum` function takes a list `l` as its argument and uses `fold_left` with the `+` operator and an initial accumulator value of `0` to compute the sum of `l`. For example:


let l = [1; 2; 3]
let sum_l = sum l (* returns 6 *)

------------------------------------------------------------------------------------------------------------------------------------------

`fold_right` is a higher-order function in OCaml that is similar to `fold_left`, but it processes the elements of a list from right to left instead of from left to right.

Here's the signature of `fold_right`:


val fold_right : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b


The first argument is a function `f` that takes an element of the list and an accumulator value and returns a new accumulator value. The second argument is the list to be processed, and the third argument is the initial accumulator value.

Here's an example implementation of `fold_right`:


let rec fold_right f l acc =
match l with
| [] -> acc
| x :: xs -> f x (fold_right f xs acc)


The implementation is similar to `fold_left`, except that it calls itself recursively on the tail of the list (`xs`) and passes the current accumulator value (`acc`) as the second argument to `f`.

Here's an example of using `fold_right` to compute the product of a list of integers:


let product l = fold_right (fun x acc -> x * acc) l 1


The `product` function takes a list `l` as its argument and uses `fold_right` with a function that multiplies the current element by the accumulator and an initial accumulator value of `1` to compute the product of `l`. For example:


let l = [1; 2; 3]
let product_l = product l (* returns 6 *)


Note: `fold_right` is often less efficient than `fold_left` because it processes the list in reverse order. This leads to an excessive stack usage for large lists.

_____________________________________________________________________________________________________________________________________________