### 5.1. Simple functions To create a recursive function we have to use this structure ```Ocaml (*normal function*) # let f = expr -> 1) evaluate expr ; 2) create & link f to the result (*recursiv function*) # let rec f = expr -> 1) create f ; 2) evaluate expr ; 3) link f to the result ``` **Exmple with factorial function** ```Ocaml # let rec fact = function | 0 -> 1 | n -> n * fact(n-1) # fact 4;; -: int = 24 ``` ![Alt](https://gitea.louisgallet.fr/lgallet/epicours/raw/branch/main/Algo/S%C3%A9minaire/assets/fact%20function%20response.png) > ⚠️ CAML have a call stack limite (it will block with stack overflow if the limit is reach) **Basic expression** ```Ocaml let rec f params = if stop condition then stop expression else recursive expression ``` To write a recurvise function we need two things 1) There always is a stop case 2) The parameters of a recursive call are different then its parent call, and go towards the stop condition ### 5.2. Down ```Ocaml # let rec countdown n = if n < 0 then () else begin print_int n ; print_newline(); countdown(n-1); end;; val countdown = int -> unit = () # countdown 3;; 3 2 1 - : unit = () ``` Flowchart of CAML evaluation ```mermaid flowchart LR A[ctd 3] --> B[ctd 2] --> C[ctd 1] --> D[ctd 0] --> E[ctd -1] --> F[ ] --> E --> D --> C --> B --> A ``` > ctd is countdown ## 5.3. Several recursive calls A function that have several recursive calls is defined like this $$ Fn = {1 -> \text{if } n\eqslantless{1} \brace{Fn+1+Fn+2} } $$ **Fibonacci functions** ```Ocaml let rec fibonacci n = if n = 0 then 0 else if n = 1 then 1 else fibonacci(n-1) + fibonacci(n-2);; let rec odd n = if n = 0 then false else even (n-1);; and even n = if n = 0 then true else add (n-1);; val add : int -> bool = val even : int -> bool = ``` An accumulator is a variable used to stock temporary the intermediaries results of a recursive operation. In CAML the syntax for the accumulator (`inv`) is: (exemple with reverse_int exercise. See 4.9 - b) ```Ocaml # let reverse_int = let rec rev inv = function | 0 -> inv | n -> rev (inv*10 + n mod 10)(n/10) in rev 0 n;; ``` ## 4.3. Complexity Exemple with egypt (4.10) vs multiply (4.6): ```Ocaml # let multiply a b = let (a,b) = if a > b then (a,b) else (b,a) in let rec mult = function | 0 -> 0 | b -> a +mult (b-1) in mult b;; ``` The best algorithm in term of complexity is the parameter that is constant/linear or logarithmic. If you have an exponential algorithm, you can put it in trash :) **Exemple with fibonacci algorithm** ```Ocaml # let rec fibo = function 0|1 -> 1 | n -> fibo (n-1) + fibo(n-2);; ``` | |res|how (for human) ?|How (for function) ?| |:----:|:----:|:----:|:----:| |0|1|def|1 call| |1|1|def|1 call| |2|2|+|3 calls| |3|3|+|5 calls| |4|5|+|9 calls| |5|8|+|15 calls| |6|13|+|14 calls| | | |$0(n)$|$O(2^n)$|
This function is not optimize because the number of calls is growing exponentially. A good function will be: ```Ocaml # let fibo n = let rec fib i fi fi_1 = if n <= i then fi else fib (i+1)(fi+fi_1)fi in fib 1 1 1 ```