---
# System prepended metadata

title: funkcyjne

---

# Funkcyjne
## Lista 2
### z1
```ocaml
let my_length = List.fold_left (fun acc _ -> acc + 1) 0
let my_rev = List.fold_left (fun acc x -> x :: acc) [] 
let my_map f xs = List.fold.right (fun x acc -> f x :: acc) xs []
let my_filter f xs = List.fold_right (fun x acc -> if f x then x :: acc else acc) xs []
let my_rev_map f = List.fold_left (fun acc x -> (f x) :: acc) [] 
```
### z2
```ocaml
let rec sublists = function
  | []    -> [[]]
  | x::xs -> let ls = sublists xs in
               List.map (fun l -> x::l) ls @ ls;;
               
#### v2

let rec sublists xs = match xs with
				| [] -> [] 
				| x :: [] -> [[x]; []]
				| x :: xs -> let ys = sublists(xs)
					     in List.fold_left (fun acc y -> (x :: y) :: acc) ys ys
```
                         
### z3
```ocaml

let rec sufiks xs = match xs with 
			| [] -> []
			| x :: [] -> [[x]; []]
			| x :: ys -> xs :: sufiks ys
            
let prefiks lista =  sufiks (List.rev lista);;

let rec prefix xs = match xs with 
			| [] -> []
			| x :: [] -> [[]; [x]]
			| x :: ys -> [] :: List.map (fun y -> x :: y ) (prefix ys)
```
### z4
```ocaml
:::spoiler nieważne
let rec insert cmp x xs = match xs with 
			| [] -> [x]
			| y :: ls ->  if cmp x y then x :: xs
				      else y :: insert cmp x ls 
			
let stupid_merge cmp xs ys = List.fold_left (fun ls x -> insert cmp x ls) ys xs
:::

# nieogonowe
let rec merge cmp l1 l2 = match (l1, l2) with
| [], a -> a
| a, [] -> a
| x :: xs, y :: ys -> 
        if cmp x  y then x :: merge cmp xs l2
                 else y :: merge cmp ys l1
else y :: merge cmp ys (x :: xs)

# ogonowe z odwracaniem
let merge_tail cmp lista1 lista2 = 
    let rec _merge cmp l1 l2 result = 
        match l1, l2 with
            | [] , [] -> result
            | [] , h :: t | h :: t , [] -> _merge cmp  [] t (h::result)
            | h1 :: t1 , h2 :: t2 -> if (cmp h1 h2) 
            then _merge cmp t1 l2 (h1::result) 
            else _merge cmp l1 t2 (h2::result) 
            in List.rev(_merge cmp lista1 lista2 []);;

let rec halve ls = match ls with
| [] -> [[]; []]
| a :: [] -> [[a]; []]
| a :: b :: ys -> let xs = halve ys in
        [(a :: List.hd xs); (b :: List.hd(List.tl xs))];;
        
        
let rec mergesort ls = match ls with
| [] -> []
| [a] -> [a]
| _ -> let xs = halve ls in
        merge (mergesort (List.hd xs)) (mergesort (List.hd (List.tl xs)));;
        
:::spoiler kornelia
let rec mergesort cmp xs = match xs with 
				| [] -> []
				| [x] -> [x]
				| xs -> let [ys;zs] = halve xs in merge cmp (mergesort cmp ys) (mergesort cmp zs)
:::

porownyywanie czasu
let time f x =
    let t = Sys.time() in
    let fx = f x in
    Printf.printf "Execution time: %fs\n" (Sys.time() -. t);
    fx
    
    
pd : time merge_tail (<=) [1;2;5;7;8] [3;4;7;10]

```


### z5 
```ocaml=
let merge_tail cmp reversed lista1 lista2 = 
    let rec _merge cmp l1 l2 result = 
        match l1, l2 with
            | [] , [] -> result
            | [] , h :: t | h :: t , [] -> _merge cmp  [] t (h::result)
            | h1 :: t1 , h2 :: t2 -> if (cmp h1 h2) == reversed
            then _merge cmp l1 t2 (h2::result) 
            else _merge cmp t1 l2 (h1::result)  
            in _merge cmp lista1 lista2 [];;
        
        
---------------- 
let merge_tail cmp lista1 lista2 = 
    let rec _merge cmp l1 l2 result = 
        match l1, l2 with
            | [] , [] -> result
            | [] , h :: t | h :: t , [] -> _merge cmp  [] t (h::result)
            | h1 :: t1 , h2 :: t2 -> if (cmp h1 h2)
            then _merge cmp l1 t2 (h2::result) 
            else _merge cmp t1 l2 (h1::result)  
            in _merge cmp lista1 lista2 [];;
            
let rec mergesort cmp xs = match xs with 
				| [] -> []
				| [x] -> [x]
				| _ -> let [ys;zs] = halve xs in merge_tail cmp (mergesort (fun a b -> not (cmp a b)) ys) (mergesort (fun a b -> not (cmp a b)) zs)
            
```

### z6
```ocaml


let rec insert x lst =
  match lst with
  | [] -> [[x]]
  | h::t -> 
    (x::lst) :: (List.map (fun el -> h::el) (insert x t));;



let rec perm lst =
  match lst with
  | [] -> [lst]
  | h::t -> 
    List.flatten (List.map (insert h) (perm t));;

```


::: spoiler Kornelia
```ocaml
(* przez wstawianie *)
let rec insert_everywhere xs y = match xs with 
					| [] -> [[y]]
					| x :: xs -> (y :: x :: xs) :: List.map (fun z -> x :: z) (insert_everywhere xs y)
                    
                    
let rec perms xs = match xs with
			| [] -> []
			| x :: [] -> [[x]]
			| x :: xs -> let ys = perms xs in List.flatten (List.map (fun s ->  insert_everywhere s x) ys)	
            
(* przez wybór *)
let rec perms2 ls = 
	let join x xs = match xs with
			| [] -> [[x]]
			| _ -> List.map (fun ys -> x :: ys) xs
	   in let rec inner ys acc = match ys with 
		| [] -> []
		| [y] -> join y (perms2 acc)
		| y :: ys -> let zs = perms2 (acc@ys) in (join y zs) @ (inner ys (y :: acc)) 
		in inner ls []
 ```           
:::

### z7
```ocaml
  type ltree =
    | Leaf
    | Node of ltree * int * int * ltree

  let make lt1 lt2 v = match lt1, lt2 with 
    | Leaf, Leaf -> Node (lt1, v, 1, lt2)
    | Node (_, _, d1, _), Node (_, _, d2, _) -> if d2 < d1 then Node (lt1, v, d2 + 1, lt2) else Node (lt2, v, d1 + 1, lt1)
    | Leaf, Node (_, _, d, _)  -> Node (lt2, v, d + 1, lt1)
    | Node (_, _, d, _), Leaf ->  Node (lt1, v, d + 1, lt2)

let deep lt = match lt with
  | Leaf -> 0
  | Node(_, _, d, _) -> d

let rec join lt1 lt2 = match lt1, lt2 with 
    | Leaf, _ -> lt2
    | _, Leaf -> lt1 
    | Node (l1, v1, d1, r1), Node (l2, v2, d2, r2) -> if v2 < v1 then let lt_new = join r2 lt1 
        in if deep lt_new > deep l2 then Node (lt_new, v2, d1 + 1, l2)
                                    else Node (l2, v2, deep lt_new + 1, lt_new)
                                                                else join lt2 lt1

let add v lt = join lt (make Leaf Leaf v)

let del_min lt = match lt with 
  | Leaf -> Leaf
  | Node (l, _, _, r) -> join l r
  
let get_min lt = match lt with
  | Leaf -> failwith "empty"
  | Node (_, v, _, _) -> v
```

ze strony
``` ocaml
type 'a leftist =  
  | Leaf 
  | Node of 'a leftist * 'a * 'a leftist * int
  
  
let singleton k = Node (Leaf, k, Leaf, 1)

let rank = function Leaf -> 0 | Node (_,_,_,r) -> r 

let rec merge t1 t2 =  
  match t1,t2 with
    | Leaf, t | t, Leaf -> t
    | Node (l, k1, r, _), Node (_, k2, _, _) ->
      if k1 > k2 then merge t2 t1 (* switch merge if necessary *)
      else 
        let merged = merge r t2 in (* always merge with right *)
        let rank_left = rank l and rank_right = rank merged in
        if rank_left >= rank_right then Node (l, k1, merged, rank_right+1)
        else Node (merged, k1, l, rank_left+1) (* left becomes right due to being shorter *)
        
let insert x t = merge (singleton x) t

let get_min = function  
  | Leaf -> failwith "empty"
  | Node (_, k, _, _) -> k

let delete_min = function  
  | Leaf -> failwith "empty"
  | Node (l, _, r, _) -> merge l r  
  
```
### z8 :(
### z9 
```ocaml=
type 'a clist = { clist : 'z. ('a -> 'z -> 'z) -> 'z -> 'z }

let cnil : = { clist = fun f z -> z}

let ccons a ls = {clist = fun f z -> f a (ls.clist f z)}

let map g ls = {clist = fun f z -> ls.clist (fun a s -> f (g a) s) z}

let append xs ys = {clist = fun f z -> xs.clist f (ys.clist f z)}

let clist_to_list ls = ls.clist List.cons [] 

let rec clist_of_list xs = match xs with 
  | [] -> cnil
  | x :: xs -> ccons x (clist_of_list xs)
  

To daje iloczyn kartezjański
let prod ls1 ls2 = ls1.clist (fun a1 z1 -> (ls2.clist (fun a2 z2 -> ccons (a1,a2) z2) z1)) cnil;;

Czy potrafisz zaimplementować funkcję analogiczną do potęgowania? NIE

```

## Lista 3

### z1

#### perm.ml
```ocaml=
module type OrderedType = sig
    type t
    val compare : t -> t -> int
end

module type S = sig
    type key
    type t
    
    (** permutacja jako funkcja *)
    val apply : t -> key -> key
    
    (** permutacja identycznościowa *)
    val id : t
    
    (** permutacja odwrotna *)
    val invert : t -> t
    
    (** permutacja która tylko zamienia dwa elementy miejscami *)
    val swap : key -> key -> t
    
    (** złożenie permutacji (jako złożenie funkcji) *)
    val compose : t -> t -> t

    (** porównywanie permutacji *)
    val compare : t -> t -> int
end

module Make(Key : OrderedType) = struct
    module Ourmap = Map.Make(Key)
    type key = Key.t
    type t = key Ourmap.t * key Ourmap.t
    
    (** permutacja jako funkcja *)
    let apply (perm : t) (value : key) = 
        if Ourmap.mem value (fst perm) 
                        then Ourmap.find value (fst perm)
                        else value
    
    (** permutacja identycznościowa *)
    let id : t = (Ourmap.empty, Ourmap.empty)

    (** permutacja odwrotna *)
    let invert (perm : t) =
        (snd perm , fst perm)
        
    (** permutacja która tylko zamienia dwa elementy miejscami *)
    let swap (e1 : key) (e2 : key) = 
        let f = (Ourmap.add e1 e2 (Ourmap.add e2 e1 Ourmap.empty)) 
        in (f, f)
    
    
    (** złożenie permutacji (jako złożenie funkcji) BRZYDKIE *)
   (* val compose (perm1 : t) (perm2 : t) =
            let map1 = union (fun key v1 v2 -> v2) 
                            (fst perm2) 
                            (Ourmap.filter (fun k v -> Key.compare k v != 0) 
                                            (Ourmap.map (apply perm2) (fst perm1)))
            in (map1, map2 - odwrotnosc map1)
*)
                
        
 let compose (perm1 :t) (perm2 : t) = 
        (Ourmap.merge 
            (fun (k : key) (v1 : key option) (v2 : key option) -> 
                match v1,v2 with
                | None, None -> None
                | _, Some(v) -> let vi = apply perm1 v in
                                    if (Key.compare k vi == 0) then None
                                        else Some(vi)
                | Some(v), None -> Some(v)         
            ) 
            (fst perm1) (fst perm2),
        Ourmap.merge
            (fun (k : key) (v1 : key option) (v2 : key option) ->
                match v1,v2 with
                | None, None -> None
                | Some(v), _ -> let vi = apply (invert perm2) v in 
                                if (Key.compare k vi == 0) then None 
                                    else Some(vi)
                | None, Some(v) -> Some(v)
            )
            (snd perm1) (snd perm2)
        )

    (** porównywanie permutacji *)
    let compare (perm1 : t) (perm2 : t) = Ourmap.compare Key.compare (fst perm1) (fst perm2)
end


```

Testy:
```ocaml=
module PermInt = Perm.Make(Int);;
let lista=[1;2;3;4];;
let perm1=PermInt.id
List.map (PermInt.apply perm1) lista
let perm2=PermInt.swap 2 4
List.map (PermInt.apply perm2) lista
List.map (PermInt.apply (PermInt.invert perm2)) lista


module PermInt = Perm.Make(Int);;
let lista=[1;2;3;4];;
let swap_23 = PermInt.swap 2 3;;   (*1 3 2 4*)
let swap_34 = PermInt.swap 3 4;; (*1 2 4 3*)
let swap_24 = PermInt.compose swap_23 swap_34;; (* 1 3 4 2*)
List.map (PermInt.apply swap_24) lista;;   
List.map (PermInt.apply (PermInt.invert swap_24)) lista;; (* 1 4 2 3 *)

let swap_32 = PermInt.swap 3 2;;
let my_id = PermInt.compose swap_23 swap_32;;
PermInt.compare my_id PermInt.id;; (* 0 *)


PermInt.compare()
```

- ocamlc -c perm.mli
- ocamlc -c perm.ml
- utop perm.cmo
W utopie : 
- open Perm;;
- module PermInt = Perm.Make(Int);;

### z2

#### .mli
``` ocaml
module type OrderedType = sig 
    type t
    val compare : t -> t -> int
end

module type Permutation = sig 
    type key
    type t
    (* permutacja jako funkcja *)
    val apply : t -> key -> key
    (* permutacja identycznosciowa *)
    val id : t
    (* permutacja odwrotna *)
    val invert : t -> t
    (* permutacja która zmienia dwa elementy miejscami *)
    val swap : key -> key -> t
    (* złożenie permutacji (jako złożenie funkcji) *)
    val compose : t -> t -> t
    (* porównanie permutacji *)
    val compare : t -> t -> int
  end

module type S = sig 
    type t
    (* czy dany element jest generowany przez zbior *)
    val is_generated : t -> t list -> bool
  end
  
  module Make(Perm : Permutation) : S with type t = Perm.t

```
#### .ml
```ocaml
module type OrderedType = sig 
    type t
    val compare : t -> t -> int
end

module type Permutation = sig 
    type key
    type t
    (* permutacja jako funkcja *)
    val apply : t -> key -> key
    (* permutacja identycznosciowa *)
    val id : t
    (* permutacja odwrotna *)
    val invert : t -> t
    (* permutacja która zmienia dwa elementy miejscami *)
    val swap : key -> key -> t
    (* złożenie permutacji (jako złożenie funkcji) *)
    val compose : t -> t -> t
    (* porównanie permutacji *)
    val compare : t -> t -> int
  end

module type S = sig 
    type t
    (* czy dany element jest generowany przez zbior *)
    val is_generated : t -> t list -> bool
end

module Make(Perm : Permutation) = struct
    type t = Perm.t
    module PermSet = Set.Make(Perm)

    let is_generated (perm : t) (perm_lst : t list) = 
      let s = PermSet.add Perm.id (PermSet.of_list perm_lst)  in
          let rec inner (perm : t) (perm_set : PermSet.t) = 
              if PermSet.mem perm perm_set then true
              else let next_set =
                  PermSet.fold (fun el acc -> 
                    PermSet.union acc 
                            (PermSet.add (Perm.invert el)
                                (PermSet.fold (fun ell acc-> 
                                                PermSet.add (Perm.compose el ell) acc )
                                            perm_set PermSet.empty)))
                                perm_set
                                perm_set
                  in if compare next_set perm_set == 0 then false 
                      else inner perm next_set
            in inner perm s      

end
          
```
ocamlc -c gen_perm.ml
utop perm.cmo gen_perm.cmo

Testy
```ocaml=
open Perm;;
open Genperm;;

module PermInt = Perm.Make(Int);;
module GenpermInt = Genperm.Make(PermInt);;
GenpermInt.is_generated (PermInt.swap 2 3) [PermInt.swap 2 3];;
let swap_23 = PermInt.swap 2 3;; 
let swap_34=PermInt.swap 3 4;;
let swap_24 = PermInt.compose swap_34 swap_23;;
GenpermInt.is_generated swap_24 [swap_23;swap_34];;
GenpermInt.is_generated swap_24 [PermInt.swap 2 5 ;swap_34];;
```


### z3, z4, z5, z6 :-0

Logic.ml
``` ocaml
type formula = 
| My_False
| Variable of string
| Implication of formula * formula

let rec string_of_formula f = match f with 
| My_False -> "⊥"
| Variable c -> c
| Implication(My_False, r) -> "⊥ -> " ^ string_of_formula r
| Implication(Variable c, r) -> c ^ " -> " ^ string_of_formula r
| Implication(l, r) -> "(" ^ string_of_formula l ^ ")" ^ " -> " ^ string_of_formula r

let pp_print_formula fmtr f =
  Format.pp_print_string fmtr (string_of_formula f)

type theorem = | Theorem of formula list * formula

let assumptions thm = match thm with 
| Theorem(a, c) -> a

let consequence thm = match thm with 
| Theorem(a, c) -> c

let pp_print_theorem fmtr thm =
  let open Format in
  pp_open_hvbox fmtr 2;
  begin match assumptions thm with
  | [] -> ()
  | f :: fs ->
    pp_print_formula fmtr f;
    fs |> List.iter (fun f ->
      pp_print_string fmtr ",";
      pp_print_space fmtr ();
      pp_print_formula fmtr f);
    pp_print_space fmtr ()
  end;
  pp_open_hbox fmtr ();
  pp_print_string fmtr "⊢";
  pp_print_space fmtr ();
  pp_print_formula fmtr (consequence thm);
  pp_close_box fmtr ();
  pp_close_box fmtr ()

let by_assumption f = Theorem([f],  f)

let imp_i f thm = Theorem(List.filter (fun x -> not(x = f)) (assumptions thm), 
        Implication(f, consequence thm))

let difference_of_lists xs ys =
  List.filter (fun x -> not (List.mem x ys)) xs
  
  let imp_e th1 th2 = match consequence th1 with
  | Implication(fi, f) -> if (fi = consequence th2)
      then Theorem(difference_of_lists (assumptions th1) (assumptions th2) @ assumptions th2, f)
      else failwith "not equal"
  | _ -> failwith "incorrect th1"

      
let bot_e f thm = match consequence thm with 
| My_False -> Theorem(assumptions thm, f)
| _ -> failwith "incorrect theorem"


(* ⊢ p → p*)

(*⊢ p → q → p*)
(*⊢ (p → q → r) → (p → q) → p → r*)
(*⊢ ⊥ → p*)


(*
open Logic;;
#install_printer pp_print_formula ;;
#install_printer pp_print_theorem ;;   
*)

```

W Logic.mli
```ocaml=
type formula = 
  | Implication of formula * formula
  | Variable of string
  | MyFalse

```



### z7 :-|

```ocaml=
(* ⊢ p → p*)
imp_i (Variable "p") (by_assumption (Variable "p"));;
(*⊢ p → q → p*)
imp_i (Variable "p") (imp_i (Variable "q") (by_assumption (Variable "p")));;
(*⊢ (p → q → r) → (p → q) → p → r*)
let pqrL = (Implication (Variable "p", Implication (Variable "q", Variable "r")))
let pqL = Implication (Variable "p", Variable "q")
let pqrT = by_assumption pqrL
let pT = by_assumption (Variable "p")
let qrT = imp_e pqrT pT
let pqT = by_assumption pqL
let qT = imp_e pqT pT
let rT = imp_e qrT qT
let prT = imp_i (Variable "p") rT 
let pqprT  = imp_i pqL prT
pqrpqprT = imp_i pqrL pqprT;;

(*⊢ ⊥ → p*)
imp_i My_False (bot_e (Variable "p") (by_assumption My_False));;
(imp_i (Variable "q") (by_assumption (Variable "p")))


```
## Lista 4
### zadanie 1

### zadanie 2

### zadanie 3-6
proof.ml
```ocaml
open Logic

type lbl_assump = (string * Logic.formula)
type incomplete_proof = 
  | Goal   of lbl_assump list * Logic.formula
  | IBot_e of lbl_assump list * Logic.formula * incomplete_proof
  | IImp_e of lbl_assump list * Logic.formula * incomplete_proof * incomplete_proof
  | IImp_i of lbl_assump list * Logic.formula * incomplete_proof
  | IComplete of Logic.theorem

type context = 
  | CEmpty
  | CGoal of lbl_assump list * Logic.formula
  | CBot_e of context * lbl_assump list * Logic.formula 
  | CImp_e of context * lbl_assump list * Logic.formula * incomplete_proof
  | CImp_i of context * lbl_assump list * Logic.formula 
  | CComplete of Logic.theorem

type proof = 
  | Complete of Logic.theorem
  | Incomplete of incomplete_proof * context

let proof g f =
  Incomplete (Goal(g, f), CEmpty)

let qed pf =
  match pf with
  | Complete(t) -> t
  | _ -> failwith "incompleted proof"

let goal pf =
  match pf with
  | Complete(t) -> None
  | Incomplete(ip, _) -> 
    match ip with
    | Goal (g, f) -> Some (g, f)
    | _ -> failwith "not a goal"


let rec goal_down incomplete_proof ctx = 
  match incomplete_proof with
  | Goal (g, f) -> Some(Incomplete(incomplete_proof, ctx))
  | IBot_e (g, f, i) -> goal_down i (CBot_e(ctx, g, f))
  | IImp_e (g, f, i1, i2) -> 
  begin
    match i1 with 
    | IComplete _ ->  goal_down i2 (CImp_e(ctx, g, f, i1))
    | _ -> goal_down i1 (CImp_e(ctx, g, f, i2))
  end
  | IImp_i (g, f, i) -> goal_down i (CImp_i(ctx, g, f))
  | IComplete (_) -> None

let rec goal_up incomplete_proof ctx = 
  match ctx with
  | CEmpty -> None
  | CGoal (g, f) -> failwith "surely won't happen"
  | CBot_e (ctx, g, f) -> goal_up (IBot_e(g, f, incomplete_proof)) ctx
  | CImp_e (ctx, g, f, i2) -> 
  begin
    match i2 with 
    | IComplete (_) -> goal_up (IImp_e(g, f, incomplete_proof, i2)) ctx
    | _ -> goal_down i2 (CImp_e(ctx, g, f, incomplete_proof))
  end
  | CImp_i (ctx, g, f) -> goal_up (IImp_i(g, f, incomplete_proof)) ctx
  | CComplete (_)-> None



let next pf =
  match pf with
  | Complete _ -> pf
  | Incomplete (ipf, ctx) -> 
    match goal_down ipf ctx with
    | None -> 
    begin
      match goal_up ipf ctx with
      | None -> failwith "You shouldn't be here"
      | Some pf -> pf
    end
    | Some pf -> pf


let intro name pf =
  match pf with
  | Complete _ -> failwith "ups"
  | Incomplete (ipf,ctx) -> 
    match ipf with
    | Goal (assm, Logic.Implication(f1, f2)) -> 
      Incomplete (IImp_i (assm, Logic.Implication(f1, f2), Goal((name, f1)::assm, f2)), ctx)
    | _ -> failwith "ups v2"

let apply f pf =
  

let apply_thm thm pf =
  (* TODO: zaimplementuj *)
  failwith "not implemented"

let apply_assm name pf =
  (* TODO: zaimplementuj *)
  failwith "not implemented"

let pp_print_proof fmtr pf =
  match goal pf with
  | None -> Format.pp_print_string fmtr "No more subgoals"
  | Some(g, f) ->
    Format.pp_open_vbox fmtr (-100);
    g |> List.iter (fun (name, f) ->
      Format.pp_print_cut fmtr ();
      Format.pp_open_hbox fmtr ();
      Format.pp_print_string fmtr name;
      Format.pp_print_string fmtr ":";
      Format.pp_print_space fmtr ();
      Logic.pp_print_formula fmtr f;
      Format.pp_close_box fmtr ());
    Format.pp_print_cut fmtr ();
    Format.pp_print_string fmtr (String.make 40 '=');
    Format.pp_print_cut fmtr ();
    Logic.pp_print_formula fmtr f;
    Format.pp_close_box fmtr ()

```

v2 (tylko zmienione funkcje)
```ocaml=
type goal = lbl_assump list * Logic.formula
type proof = 
  | Complete of Logic.theorem
  | Incomplete of goal * context

let proof g f =
  Incomplete ((g, f), CEmpty)

let rec goal pf =
  match pf with
  | Complete(t) -> None
  | Incomplete(ip, _) -> Some(ip)

```
## Lista 5

### zadanie 1 
``` ocaml
let fib_f fib n =
if n <= 1 then n
else fib (n-1) + fib (n-2)

let rec fix f x = f (fix f) x

let fib = fix fib_f

let rec fix_with_limit n f x = 
  if (n != 0) 
    then f (fix_with_limit (n - 1) f) x 
    else failwith "Limit exceeded";;

let memo = Hashtbl.create 1000;;

let rec fix_memo f x = 
  match Hashtbl.find_opt memo (Hashtbl.hash x) with
  | Some c -> c
  | None -> let a = f (fix_memo f) x in
      begin
        Hashtbl.add memo (Hashtbl.hash x) a;
        a
      end
```

### zadanie 3
``` ocaml

type 'a lazy_tree =
  | LazyNode of (unit -> 'a lazy_tree) * 'a * (unit -> 'a lazy_tree)

let rec lazy_fraction_tree a b c d =
  LazyNode (
    (fun () ->
        lazy_fraction_tree a b (a + c) (b + d)),
    (a + c, b + d),
    (fun () ->
        lazy_fraction_tree (a + c) (b + d) c d)
  )

```
### zadanie 4 rozwarstwia sie :(
``` ocaml
type 'a dllist = 'a dllist_data lazy_t
and 'a dllist_data =
{ prev : 'a dllist;
  elem : 'a;
  next : 'a dllist
}

let prev : 'a dllist -> 'a dllist = 
  function xs -> (Lazy.force xs).prev

let elem : 'a dllist -> 'a = 
  function xs -> (Lazy.force xs).elem

let next : 'a dllist -> 'a dllist =
  function xs -> (Lazy.force xs).next

let rec of_list (xs : 'a list) : 'a dllist = 
  match xs with
  | [] -> failwith "empty list"
  | x :: [] -> let rec dd = lazy {prev = dd; elem = x; next = dd} in dd
  | x :: y :: [] ->  
    let rec ds = lazy {prev = dd; elem = x; next = dd}
      and
      dd = lazy {prev = ds; elem = y; next = ds} in ds
  | x :: xs ->    
    lazy {prev = of_list (begin match List.rev (x::xs) with 
                          | y :: ys -> y :: List.rev ys 
                          |_ ->  failwith "err" end); 
          elem = x; 
          next = of_list (xs @ x :: [])}  
                  
let xs = of_list [8;9;10]
let () = assert (elem xs = 8)
let () = assert (elem (prev (next xs)) = elem xs)
(*
let () = assert (prev (next xs) == xs) (*        :(       *)
*)

```
### zadanie 6
``` ocaml
type 'a to_lazy =
  | Lazy of (unit -> 'a) 
  | Value of 'a
  | Evaluating

type 'a my_lazy = 'a to_lazy ref

let force : 'a my_lazy -> 'a =
  fun ml -> 
    match !ml with
    | Lazy f   -> 
      ml := Evaluating; 
      let v = f () in 
      ml := Value(v); 
      v 
    | Value v  -> v
    | Evaluating -> failwith "Evaluating"

let fix (f : 'a my_lazy -> 'a) : 'a my_lazy =
  let rec lazy_value = ref (Lazy (fun () -> f lazy_value)) in
  lazy_value    

type 'a lazy_list =
  | Nil
  | Cons of 'a * 'a lazy_list my_lazy

let hd : 'a lazy_list -> 'a =
  function
  | Nil -> failwith "Empty list"
  | Cons(x, _) -> x

let tl : 'a lazy_list -> 'a lazy_list =
  function
  | Nil -> failwith "Empty list"
  | Cons(_, xs) -> force xs

let rec nth : 'a lazy_list -> int -> 'a = 
  fun ll n -> 
    if n < 0 then failwith "Index out of bounds" 
    else 
      if n == 0 then hd ll
      else nth (tl ll) (n - 1)


let stream_of_ones : int lazy_list my_lazy = 
  fix (fun stream_of_ones -> Cons (1, stream_of_ones))

(*
  nth (force stream_of_ones) 5   
*)


```
### zadanie 7
``` ocaml
type 'a to_lazy =
  | Lazy of (unit -> 'a) 
  | Value of 'a
  | Evaluating

type 'a my_lazy = 'a to_lazy ref

let force : 'a my_lazy -> 'a =
  fun ml -> 
    match !ml with
    | Lazy f   -> 
      ml := Evaluating; 
      let v = f () in 
      ml := Value(v); 
      v 
    | Value v  -> v
    | Evaluating -> failwith "Evaluating"

let fix (f : 'a my_lazy -> 'a) : 'a my_lazy =
  let rec lazy_value = ref (Lazy (fun () -> f lazy_value)) in
  lazy_value    

(* z7 ---------------------------------------------------- *)

type 'a lazy_list =
  | Nil
  | Cons of 'a * 'a lazy_list my_lazy

let rec nth xs n =
  match xs with
  | Nil -> raise Not_found
  | Cons(x, xs) ->
    if n = 0 then x
    else nth (force xs) (n-1)

let rec filter (p : 'a -> bool) (xs : 'a lazy_list) : ('a lazy_list) = 
  match xs with
  | Nil                  -> Nil
  | Cons(x, xs) when p x -> Cons(x, ref (Lazy (fun () -> (filter p (force xs)))))
  | Cons(_, xs)          -> filter p (force xs)

let rec take_while p xs =
  match xs with
  | Cons(x, xs) when p x -> Cons(x, ref (Lazy (fun () -> (take_while p (force xs)))))
  | _ -> Nil

let rec for_all p xs =
  match xs with
  | Nil -> true
  | Cons(x, xs) -> p x && for_all p (force xs)

let rec nats_from n = 
  Cons(n, ref (Lazy (fun () -> (nats_from (n+1)))))
let nats = nats_from 0

let rec primes =
  Cons(2, ref (Lazy (fun () -> (filter is_prime (nats_from 3)))))
and is_prime n =
  primes
  |> take_while (fun p -> p * p <= n)
  |> for_all (fun p -> n mod p <> 0)
```
### zadanie 8
``` ocaml
open Seq
type _ fin_type =
  | Unit : unit fin_type
  | Bool : bool fin_type
  | Pair : 'a fin_type * 'b fin_type -> ('a * 'b) fin_type

  let rec all_values : type a. a fin_type -> a Seq.t =
    fun ftype -> match ftype with
    | Unit -> List.to_seq [()]
    | Bool -> List.to_seq [true; false]
    | Pair (fst_type, snd_type) ->
      flat_map
        (fun fst_val ->
           map (fun snd_val -> (fst_val, snd_val))
                (all_values snd_type))
        (all_values fst_type)

```
### zadanie 9
``` ocaml
type _ fin_type =
| Unit : unit fin_type
| Bool : bool fin_type
| Pair : 'a fin_type * 'b fin_type -> ('a * 'b) fin_type
| Empty : empty fin_type
| Either : 'a fin_type * 'b fin_type -> ('a, 'b) Either.t fin_type
and empty = |

let rec all_values : type a. a fin_type -> a Seq.t =
  function
  | Unit -> List.to_seq [()]
  | Bool -> List.to_seq [true; false]
  | Pair (a, b) -> 
    Seq.flat_map 
      (fun x -> 
        Seq.map 
          (fun y -> (x, y)) 
          (all_values b))
      (all_values a)
  | Empty -> Seq.empty
  | Either (a, b) -> 
    let av = all_values a and bv = all_values b in
    Seq.append 
      (Seq.map (fun x -> Either.left x) av)
      (Seq.map (fun y -> Either.right y) bv)

```
### zadanie 10
```ocaml
module Seq = struct
  include Seq
  let rec for_all : ('a -> bool) -> 'a Seq.t -> bool =
    fun pred seq ->
      match seq () with
      | Seq.Nil -> true
      | Seq.Cons (x, xs) -> pred x && for_all pred xs
  let is_empty seq =
    match seq () with
    | Seq.Nil -> true
    | _ -> false
end

type _ fin_type =
| Unit : unit fin_type
| Bool : bool fin_type
| Pair : 'a fin_type * 'b fin_type -> ('a * 'b) fin_type
| Empty : empty fin_type
| Either : 'a fin_type * 'b fin_type -> ('a, 'b) Either.t fin_type
| Function : 'a fin_type * 'b fin_type -> ('a -> 'b) fin_type
and empty = |

let rec all_values : type a. a fin_type -> a Seq.t =
  function
  | Unit -> List.to_seq [()]
  | Bool -> List.to_seq [true; false]
  | Pair (a, b) -> 
    Seq.flat_map 
      (fun x -> 
        Seq.map 
          (fun y -> (x, y)) 
          (all_values b))
      (all_values a)
  | Empty -> Seq.empty
  | Either (a, b) -> 
    let av = all_values a and bv = all_values b in
    Seq.append 
      (Seq.map (fun x -> Either.Left x) av)
      (Seq.map (fun y -> Either.Right y) bv)
  | Function (a, b) -> 
    all_functions a Seq.empty (all_values a) (all_values b)
      
and equal_at : type a. a fin_type -> a -> a -> bool =
  fun ty x y ->
    match ty with
    | Unit -> x = y
    | Bool -> x = y
    | Pair (a, b) ->
      equal_at a (fst x) (fst y) && 
      equal_at b (snd x) (snd y)
    | Empty -> true 
    | Either (a, b) ->
      (match (x, y) with
      | (Left x, Left y) -> equal_at a x y
      | (Right x, Right y) -> equal_at b x y
      | _ -> false)
    | Function (a, b) ->
      let all_inputs = all_values a in
      Seq.for_all (fun input -> equal_at b (x input) (y input)) all_inputs

and all_functions : type a b. a fin_type -> (a -> b) Seq.t -> a Seq.t -> b Seq.t -> (a -> b) Seq.t  =
  fun t seq a b ->
  match a () with
  | Seq.Nil -> seq
  | Seq.Cons (a, xs) -> 
    let seq =
    if Seq.is_empty seq then
      Seq.map (fun b -> fun _ -> b) b
    else 
      Seq.flat_map 
        (fun f -> 
          Seq.map (fun b -> 
            fun x -> if (equal_at t x a) then b
            else f x) b)
        seq
    in all_functions t seq xs b 

(* test *)
let xs = all_values (Function(Bool, Bool))
let ys = Seq.map (fun x -> List.map (fun y -> x y) (List.of_seq (all_values Bool))) xs 
let ls = List.of_seq ys

 


```

## Lista 6

### zadanie 1
``` ocaml
type ('a, 'b) format = (string -> 'b) -> string -> 'a

let int (k : string -> 'a) = 
  fun (s : string) (i : int) -> k (s ^ (string_of_int i))

let str (k : string -> 'a) = 
  fun (s1 : string) (s2 : string) -> k (s1 ^ s2)
  
let lit (sn : string) (k : string -> 'a) = 
  fun (s : string) -> k(s ^ sn)

let (^^) (f1 : ('a, 'b) format) (f2 : ('b, 'c) format) (k : string -> 'c) =
  f1(f2 k)

let ksprintf (f : ('a, 'b) format) (k : string -> 'b) = 
  f k ""

let sprintf (f : ('a, string) format) =
  ksprintf f (fun x -> x);;

sprintf (lit "Ala ma " ^^ _int ^^ lit " kot" ^^ _str ^^ lit ".") 5 "ów"

```
### zadanie 2
``` ocaml

```
### zadanie 3
``` ocaml
exception Error of string

let for_all pred ls =
        try List.fold_left (fun acc a -> if not (pred a) then raise (Error "oops") else acc) true ls with Error _ -> false

let mult_list ls =
        try List.fold_left (fun acc a -> if a==0 then raise (Error "mult") else acc*a) 1 ls with Error _ ->0

let sorted ls=
        try fst(List.fold_left (fun acc a ->
                                        if a < snd(acc)
                                        then raise (Error "unsort")
                                        else (true, a))
                                (true, (List.hd ls))
                                (List.tl ls))
        with Error _ -> false
```
### zadanie 4
``` ocaml
let rec fold_left_cps f acc xs=
        match xs with 
        | []    -> acc
        | x::xs -> f acc x (fun lacc -> fold_left_cps f lacc xs)

let fold_left f acc xs=
      fold_left_cps (fun acc x k -> k (f acc x)) acc  

```
### zadanie 5
``` ocaml
let for_all pred xs =
        fold_left_cps (fun acc x k ->
                        if pred x
                        then k acc
                        else false
                        ) true xs

let mult_list xs = 
        fold_left_cps (fun acc x k ->
                        if x==0
                        then 0
                        else k (acc * x)
        ) 1 xs
let sorted xs =
        fold_left_cps (fun acc x k ->
                        if x>snd(acc)
                        then k (true,x)
                        else (false,x)
        ) (true,(List.hd xs)) (List.tl xs)
        |> fst

```

## Lista 7

### zadanie 1, 2
```ocaml
module type RandomMonad = sig
  type 'a t
  val return : 'a -> 'a t
  val bind : 'a t -> ('a -> 'b t) -> 'b t
  val random : int t
  end

module RS : sig 
  include RandomMonad 
  val run : int -> 'a t -> 'a
end = struct
  type 'a t = int -> 'a * int
  let return x seed = (x, seed) 
  let run seed f = fst (f seed)
  let random a = 
    let b = 16807 * (a mod 127773) - 2836 * (a / 127773) in
    if b > 0 then (b, b) else (b + 2147483647, b + 2147483647)
  (* (x : int -> 'a * int) (f : 'a -> int -> 'b * int) -> (int -> 'b * int) *)
  let bind x f = 
    fun s1 -> let (v, s2) = x s1 in
    f v s2
end

module Shuffle(R : RandomMonad) : sig
  val shuffle : 'a list -> 'a list R.t
end = struct
  let rec chosen_rest idx xs = 
    match xs with
    | [] -> failwith "empty list"
    | x :: xs -> 
      if idx = 0 then (x, xs)
      else let (v, xs) = chosen_rest (idx - 1) xs in
      (v, x :: xs) 
  let rec shuffle xs = 
    match xs with
    | [] -> R.return []
    | _ -> 
      R.bind 
        R.random 
        (fun r -> let idx = r mod List.length xs in
        let (hd, tl) = chosen_rest idx xs in
        R.bind (shuffle tl) (fun shuffled_tl -> R.return (hd :: shuffled_tl)))
end

(*
  module SH = Shuffle(RS);;
  RS.run 0 (SH.shuffle [1;2;3;4;5;6;7;8]);;
  RS.run 23 (SH.shuffle [1;2;3;4;5;6;7;8]);;

  RS.run 1 (RS.bind RS.random (fun x -> RS.return (RS.run x RS.random)));;
*)
```


### zadanie 3
```ocaml
module IdMonad : sig
  type 'a t
  val return : 'a -> 'a t
  val bind : 'a t -> ('a -> 'b t) -> 'b t
end = struct
  type 'a t = 'a
  let return x = x
  let bind x f = f x
end

module DeferredMonad : sig
  type 'a t
  val return : 'a -> 'a t
  val bind : 'a t -> ('a -> 'b t) -> 'b t
end = struct
  type 'a t = unit -> 'a
  let return x = fun () -> x
  let bind x f = f (x ())
end
```

### zadanie 4
#### er
``` ocaml
  module type Monad = sig
    type 'a t
    val return : 'a -> 'a t
    val bind : 'a t -> ('a -> 'b t) -> 'b t
  end
  
  module Err : sig
    include Monad
    val fail : 'a t
    val catch : 'a t -> (unit -> 'a t) -> 'a t
    val run : 'a t -> 'a option
  end = struct
    type 'r ans = 'r option
    type 'a t = { run :  ('a -> 'a ans) -> 'a ans }
  
    let run m = m.run (fun a -> Some a)
    let return x = {run = fun cont -> cont x}
    let fail = {run = fun _ -> None}
  
    let bind m f =
      { run = fun cont ->
          match run m with
          | None -> None
          | Some x -> (f x).run cont }
  
    let catch m f =
  { run = fun cont ->
      match run m with
      | Some x -> Some x
      | None -> (f ()).run cont }

  end
  
  Err.run (Err.bind (Err.return 1) (fun x -> Err.return (x+1)));;

```
#### bt 
``` ocaml
  module type Monad = sig
    type 'a t
    val return : 'a -> 'a t
    val bind : 'a t -> ('a -> 'b t) -> 'b t
  end
  
  module BT : sig
    include Monad
    val fail : 'a t
    val flip : bool t
    val run : 'a t -> 'a Seq.t
  end = struct
    type 'r ans = 'r Seq.t
    type 'a t = { run :  ('a -> 'a ans) -> 'a ans }
  
    let run m = m.run (fun a -> List.to_seq [a])
    let return x = {run = fun cont -> cont x}
    let fail = {run = fun _ -> Seq.empty}
    let flip = 
      { run = fun cont -> 
        Seq.flat_map cont (List.to_seq [true; false]) }


    let bind m f =
      { run = fun cont ->
          Seq.flat_map (fun a -> (f a).run cont) (run m) }
    
  end
  
  let (let* ) = BT.bind

let rec select a b =
  if a >= b then BT.fail
  else
    let* c = BT.flip in
    if c then BT.return a
    else select (a+1) b

let triples n =
  let* a = select 1 n in
  let* b = select a n in
  let* c = select b n in
  if a*a + b*b = c*c then BT.return (a, b, c)
  else BT.fail
 
```
``` ocaml
  module type Monad = sig
    type 'a t
    val return : 'a -> 'a t
    val bind : 'a t -> ('a -> 'b t) -> 'b t
  end
  
  module St(State : sig type t end) : sig
    include Monad
    val get : State.t t
    val set : State.t -> unit t
    val run : State.t -> 'a t -> 'a
  end = struct
    type 'a ans = State.t -> 'a * State.t
    type 'a t = { run : 'r. ('a -> 'r ans) -> 'r ans }

    let return x = {run = fun cont -> cont x}
  
    let run s m = fst (m.run (fun a s2 -> (a, s2)) s)

    let set s = {
      run = fun cont _ -> cont () s
    }

    let get = {
      run = fun cont s -> cont s s
    }


    let bind m f ={
      run = fun cont -> 
        m.run (fun a -> (f a).run cont)
    }
    
  end
  
  module CounterState = struct
    type t = int
  end
  
  module CounterMonad = St(CounterState)
  
  open CounterMonad
  
  let increment_and_get : int t =
    bind get (fun current_count ->
      bind (set (current_count + 1)) (fun () ->
        return current_count
      )
    )
  
  let example () =
    let initial_state = 0 in
    let result = run initial_state increment_and_get in
    Printf.printf "Final Counter Value: %d\n" result
  
  (* Run the example *)
  let () = example ()
  
```
### Zadanie 5
```ocaml!
type 'a regexp =
  | Eps
  | Lit of ('a -> bool)
  | Or of 'a regexp * 'a regexp
  | Cat of 'a regexp * 'a regexp
  | Star of 'a regexp

let ( +% ) r1 r2 = Or(r1, r2)
let ( *% ) r1 r2 = Cat(r1, r2)

(** Obliczenia z nawrotami *)
module BT : sig
  type 'a t

  val return : 'a -> 'a t
  val bind   : 'a t -> ('a -> 'b t) -> 'b t

  (** Brak wyniku *)
  val fail : 'a t
  (** Niedeterministyczny wybór -- zwraca true, a potem false *)
  val flip : bool t

  val run : 'a t -> 'a Seq.t
end = struct
  (* Obliczenie typu 'a to leniwa lista wszystkich możliwych wyników *)
  type 'a t = 'a Seq.t

  let return x = List.to_seq [ x ]
  let rec bind m f = Seq.flat_map f m

  let fail = Seq.empty
  let flip = List.to_seq [ true; false ]

  let run m = m
end

let rec match_regexp (regex : 'a regexp) (xs : 'a list) : 'a list option BT.t =  
  match regex, xs with
  | Eps, [] -> BT.return None
  | Eps, xs -> BT.return (Some xs)
  | Lit _, [] -> BT.fail
  | Lit p, x :: xs -> 
    if p x then BT.return (Some xs)
    else BT.fail
  | Or (r1, r2), _ ->
    BT.bind BT.flip (fun flip_opt ->
      if flip_opt then match_regexp r1 xs else match_regexp r2 xs)
  | Cat (r1, r2), _ -> 
    BT.bind (match_regexp r1 xs) (fun result -> 
      match result with
      | Some x -> match_regexp r2 x
      | None -> match_regexp r2 xs)
  | Star r, _ -> BT.bind (match_regexp r xs) (fun res ->
      match res with
        | Some ys -> BT.bind BT.flip (fun flip_opt ->
          if flip_opt then BT.return (Some ys)
          else match_regexp (Star r) ys)
        | None -> BT.fail)

        (* | Star r, _ ->
          BT.bind BT.flip (fun flip_opt ->
            if flip_opt then
              BT.return None
            else
              match_regexp (Cat (r, Star r)) xs) *)
      
(*
   List.of_seq 
         (BT.run 
             (match_regexp
                      (Lit ((<>) 'a')) 
                      ['b';'c']));;

   List.of_seq 
         (BT.run 
             (match_regexp
                      (Star (Lit ((<>) 'o'))) 
                      ['s';'a';'k';'o';'p']));;

   List.of_seq 
    (BT.run 
        (match_regexp
                (Star (Star (Lit ((<>) 'k')))) 
                ['x';'a';'k']));;
  List.of_seq 
    (BT.run 
        (match_regexp
                (Star (Star (Lit ((<>) 'b')) +% (Lit ((=) 'b') *% Lit ((=) 'a')))) 
                ['s';'a';'k';'o';'p']));;

  Or działa z potencjalnymi duplikatami, stary też ale bez None
*)





```

### Zadanie 6
```ocaml!
module SBT(State : sig type t end) : sig
    type 'a t
    val return : 'a -> 'a t
    val bind : 'a t -> ('a -> 'b t) -> 'b t
    val fail : 'a t
    val flip : bool t
    val get : State.t t
    val put : State.t -> unit t
    val run : State.t -> 'a t -> 'a Seq.t
  end = struct
    type 'a t = State.t -> ('a * State.t) Seq.t
    let return x s = List.to_seq [(x, s)]
    let flip s = List.to_seq [(true, s); (false, s)]
    let get s = List.to_seq [(s, s)]
    let put s1 _ = List.to_seq [((), s1)]
    let fail _ = Seq.empty 
    let run s m = Seq.map (fun x -> fst x) (m s)
    let bind m f s = 
      Seq.flat_map (fun x -> f (fst x) (snd x)) (m s)
  end
```
### zadanie 8
```
type symbol = string

type 'v term =
| Var of 'v
| Sym of symbol * 'v term list

let return (a: 'v): 'v term =
  Var(a)

let rec bind (a: 'v term) (f: 'v -> 'v term): 'v term = 
  match a with
  | Var v -> f v
  | Sym (sym, terms) -> Sym(sym, List.map (fun t -> bind t f) terms)

```

## Lista 8
### zadania ?-?, trochę działa
```haskell=
{-# LANGUAGE LambdaCase #-}
import Data.Char (toLower)
import System.IO (isEOF)

main :: IO ()
main = putStrLn ":)"

-- z1 
echoLower :: IO ()
echoLower = do
    input <- getLine
    if not (null input)
    then do
        putStrLn $ map Data.Char.toLower input
        echoLower
    else
        return ()

-- z2
data StreamTrans i o a
    = Return a
    | ReadS (Maybe i -> StreamTrans i o a)
    | WriteS o (StreamTrans i o a)

toLower :: StreamTrans Char Char ()
toLower =
    ReadS $ \case
        Just c -> WriteS (Data.Char.toLower c) Main.toLower
        Nothing -> Return ()

runIOStreamTrans :: StreamTrans Char Char a -> IO a
runIOStreamTrans (Return a) = return a
runIOStreamTrans (ReadS f) = do
    input <- getChar
    if input == '\n'
        then runIOStreamTrans (f Nothing)
        else do
            runIOStreamTrans (f (Just input))
runIOStreamTrans (WriteS o st) = do
    putChar '\n' 
    putChar o
    putChar '\n' 
    runIOStreamTrans st

-- z3
listTrans :: StreamTrans i o a -> [i] -> ([o], a)
listTrans (Return a) xs = ([], a)
listTrans (ReadS f) [] = listTrans (f Nothing) []
listTrans (ReadS f) (x:xs) = listTrans (f (Just x)) xs
listTrans (WriteS o cont) xs =
  let (output, result) = listTrans cont xs
  in (o : output, result)

-- z6

catchOutput :: StreamTrans i o a -> StreamTrans i b (a, [o])
catchOutput (Return a) = return (a, [])
catchOutput (ReadS f) = do
    input <- getChar
    if input == '\n'
        then catchOutput (f Nothing)
        else do
            catchOutput (f (Just input))
catchOutput (WriteS o st) = 
    catchOutput ( ReadS $ \case
        Just c -> WriteS (o : c : []) st
        Nothing -> Return ()) 



-- z7

data BF
    = MoveR     -- >
    | MoveL     -- <
    | Inc       -- +
    | Dec       -- -
    | Output    -- .
    | Input     -- ,
    | While [BF]-- [ ]

brainfuckParser :: StreamTrans Char BF ()
brainfuckParser =     
    ReadS $ \case
        Just c -> WriteS (parse c) brainfuckParser
        Nothing -> Return ()

parse :: Char -> BF
parse '>' = MoveR
parse '<' = MoveL
parse '+' = Inc
parse '-' = Dec
parse ',' = Input
parse '.' = Output
```


