---
# System prepended metadata

title: Lista 3

---

###### tags: pf-dabi

# Lista 3

## Zadanie 3
```ocaml=
type formula = 
| Var of string
| False
| Implication of formula * formula
```

## Zadanie 4
```ocaml=
let rec string_of_formula f =
  match f with
  | Var(var_name) -> var_name
  | False -> "⊥"
  | Implication(f1, f2) ->
    match f1 with
    | Implication(_, _) -> "(" ^ (string_of_formula f1) ^ ") -> " ^ (string_of_formula f2)
    | Var(_) | False -> (string_of_formula f1) ^ " -> " ^ (string_of_formula f2)
```

## Zadanie 5
```ocaml=
type theorem = formula list * formula

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

let consequence thm =
  match thm with 
  | (_, c) -> c
```

## Zadanie 6
```ocaml=
type formula =
| Pin
| Var of string
| Implies of formula * formula

let by_assumption f = ([f], f)

let imp_i f thm = 
   (List.filter (fun x -> x <> f) (assumptions thm),
   (Implies(f, (consequence thm))))

let imp_e th1 th2 =
  match (consequence th1) with 
  | Implies(a, b)  -> 
    if a = (consequence th2) then ((assumptions th1) @ (assumptions th2), b)
    else failwith " "
  | _ -> failwith " "
 
let bot_e f thm =
  if (consequence thm) = Pin then 
    (assumptions thm, f)
  else failwith " "
```

---

# Lista 4

## Zadania 3-6

```ocaml=
open Logic

type no_target_proof =
| Empty of (string * formula) list * formula
| ImpI of no_target_proof * (string * formula) list * formula
| ImpE of no_target_proof * no_target_proof * (string * formula) list * formula
| BotE of no_target_proof * (string * formula) list * formula
| Complete of theorem

and context = 
| Root
| Left of context * no_target_proof * (string * formula) list * formula
| Right of no_target_proof * context * (string * formula) list * formula
| DownB of context * (string * formula) list * formula
| DownI of context * (string * formula) list * formula


type proof = context * no_target_proof


let proof g f =
  (Root, Empty(g, f))

let qed (ctx, pf) =
  match pf with
  | Complete(t)   -> t
  | _             -> failwith "Dowód nieukończony"

let goal (ctx, pf) =
  match pf with
  | Empty(g, f) -> Some(g, f)
  | _           -> None

let rec next_up (ctx, pf) = 
  match pf with
  | Complete(t) -> begin match ctx with 
                   | Root -> (ctx, pf)
                   | DownB(ctx, g, f)      -> next_up (ctx, Complete(bot_e f t))
                   | DownI(ctx, g, f)      -> next_up (ctx, Complete(imp_i f t))
                   | Left(ctx, pf2, g, f)  -> begin match pf2 with
                                              | Complete(t2) -> next_up (ctx, Complete(imp_e t t2))
                                              | _ -> next_right (ctx, ImpE(pf, pf2, g, f))
                                              end
                   | Right(pf2, ctx, g, f) -> begin match pf2 with
                                              | Complete(t2) -> next_up (ctx, Complete(imp_e t2 t))
                                              | _ -> next_left (ctx, ImpE(pf2, pf, g, f))
                                              end
                   end
  | _           -> begin match ctx with
                   | Root                  -> next_left (ctx, pf)
                   | DownB(ctx, g, f)      -> next_up (ctx, BotE(pf, g, f))
                   | DownI(ctx, g, f)      -> next_up (ctx, ImpI(pf, g, f))
                   | Left(ctx, pf2, g, f)  -> next_right (ctx, ImpE(pf, pf2, g, f))
                   | Right(pf2, ctx, g, f) -> next_up (ctx, ImpE(pf2, pf, g, f))
                   end


and next_left (ctx, pf) =
  match pf with
  | Empty(_, _) | Complete(_) -> (ctx, pf)
  | ImpI(pf, g, f)            -> next_left (DownI(ctx, g, f), pf)
  | BotE(pf, g, f)            -> next_left (DownB(ctx, g, f), pf)
  | ImpE(pf1, pf2, g, f)      -> begin match pf1 with
                                 | Complete(_) -> next_right (ctx, pf)
                                 | _           -> next_left (Left(ctx, pf2, g, f), pf1)
                                 end 

and next_right (ctx, pf) =
  match pf with 
  | ImpE(pf, pf2, g, f) -> begin match pf2 with
                           | Complete(_) -> next_up (ctx, pf)
                           | _           -> next_left (Right(pf, ctx, g, f), pf2)
                           end
  | _                   -> next_left (ctx, pf)


let next (ctx, pf) =
  match pf with
  | Complete(_) -> failwith "Nie ma więcej dziur"
  | _           -> next_up (ctx, pf)

let intro name (ctx, pf) =
  match goal (ctx, pf) with
  | None       -> failwith "Dowód ukończony"
  | Some(g, f) -> match f with
                  | Implication(left, right) -> (DownI(ctx, g, left), Empty((name, left) :: g, right))
                  | _                        -> failwith "Celem musi być implikacja"

                  
let rec far_right f = 
  match f with 
  | Implication(_, right) -> far_right right
  | _                     -> f

let rec apply_aux f (ctx, pf) g phi acc =
  if f = phi then
    ctx, acc
  else 
    let r = far_right f in
    if r <> phi && r <> False then
      failwith "Dowód niepoprawny"
    else
      match f with
      | False                    -> DownB(ctx, g, phi), acc
      | Implication(left, right) -> let (ctx2, _) = apply_aux right (ctx, pf) g phi (ImpE(acc, Empty(g, left), g, right)) in
                                    Left(ctx2, Empty(g, left), g, right), acc
      | _                        -> failwith "Miejsce nieosiągalne" 
                          

let apply f (ctx, pf) =
  match goal (ctx, pf) with
  | None         -> failwith "Nic do udowodnienia"
  | Some(g, phi) -> next_up (apply_aux f (ctx, pf) g phi (Empty(g, f)))
                                           
let apply_thm thm (ctx, pf) =
  match goal (ctx, pf) with
  | None         -> failwith "Nic do udowodnienia"
  | Some(g, phi) -> next_up (apply_aux (consequence thm) (ctx, pf) g phi (Complete(thm)))

let apply_assm name (ctx, pf) =
  match goal (ctx, pf) with
  | None         -> failwith "Nic do udowodnienia"
  | Some(g, phi) -> apply_thm (by_assumption (List.assoc name g)) (ctx, pf)

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 ();
      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 ();
    pp_print_formula fmtr f;
    Format.pp_close_box fmtr ()

```

## Zadanie 7

```ocaml=
#install_printer Logic.pp_print_formula;;
#install_printer Logic.pp_print_theorem;;
#install_printer Proof.pp_print_proof;;

open(Proof)
open(Logic)

let p = Variable("p");;
let q = Variable("q");;
let r = Variable("r");;
let f = Implication(p, Implication(Implication(p ,q), q));;


let f1 = Implication(
    Implication(
      p, 
      Implication(
        q, 
        r
        )
    ), 
    Implication(
      Implication(
        p, 
        q
        ),
      Implication(
        p, 
        r
        )
    ) 
);;
proof [] f1 |> intro "1" |> intro "2" |> intro "3" |> apply_assm "1" |> apply_assm "3" |> apply_assm "2" |> apply_assm "3" |> qed;;

let f2 = Implication(
  Implication(
    Implication(
      Implication(
        p,
        False
      ),
      p
    ),
    p
  ), 
  Implication(
    Implication(
      Implication(
        p,
        False
      ),
      False
    ),
    p
  )
);;
proof [] f2 |> intro "1" |> intro "2" |> apply_assm "1" |> intro "3" |> apply_assm "1" |> apply_assm "2" |> apply_assm "3" |> qed;;

let f3 = Implication(
  Implication(
    Implication(
      Implication(
        p,
        False
      ),
      False
    ),
    p
  ), 
  Implication(
    Implication(
      Implication(
        p,
        False
      ),
      p
    ),
    p
  )
);;

proof [] f3 |> intro "1" |> intro "2" |> apply_assm "1" |> intro "3" |> apply_assm "3" |> apply_assm "2" |> apply_assm "3" |> qed;;
```


---

# Lista 5


## Zadania 1 & 2

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

let fib_f fib n =
    if n <= 1 then n
    else fib (n - 1) + fib (n - 2)


let fib = fix fib_f

let rec fix_with_limit limit f x =
    if limit > 0 then f (fix_with_limit (limit - 1) f) x
    else failwith "Max recursion depth reached"

let fix_memo f =
    let memory = Hashtbl.create 100 in
    let rec fix memory f x =
        match (Hashtbl.find_opt memory x) with
        | None -> let result = f (fix memory f) x
        in Hashtbl.add memory x result; result
        | Some v -> v
    in f (fix memory f)
        
type 'a fix = Roll of ('a fix -> 'a);;
let unroll (Roll x) = x;;
let fix2 f = (fun x a -> f (unroll x x) a) (Roll (fun x a -> f (unroll x x) a));;


let fib0 = ref (fun x -> x);;
let fibm n = if n < 2 then n else (!fib0 (n-1)) + (!fib0 (n-2));;
fib0 := fibm;;



let fixx f x=
    let prefix = ref (fun a -> failwith "undefined") in
    (prefix := fun g ->g (!prefix g) );f (!prefix f) x
```

## Zadanie 4 & 5
```ocaml=
type 'a lazy_cycle = 'a data lazy_t
and 'a data = {
    prev : 'a lazy_cycle;
    elem : 'a;
    next : 'a lazy_cycle;
}

let prev x = (Lazy.force x).prev
let elem x = (Lazy.force x).elem
let next x = (Lazy.force x).next

let of_list xs = 
    let len = List.length xs in
    let add n = (n + 1) mod len in
    let sub n = (n - 1 + len) mod len in
    let rec next n x = 
        let rec cur = lazy({
            prev = x;
            elem = List.nth xs n;
            next = next (add n) cur;
        }) in
        cur in
    let rec prev n x = 
        let rec cur = lazy ({
            prev = prev (sub n) cur;
            elem = List.nth xs n;
            next = x;
        }) in
        cur in
    let rec head = lazy({
        prev = prev (sub 0) head;
        elem = List.nth xs 0;
        next = next (add 0) head;
    }) in
    head
    
let integers = 
    let rec next n x = 
        let rec cur = lazy({
            prev = x;
            elem = n;
            next = next (n + 1) cur;
        }) in
        cur in
    let rec prev n x = 
        let rec cur = lazy ({
            prev = prev (n - 1) cur;
            elem = n;
            next = x;
        }) in
        cur in
    let rec zero = lazy({
        prev = prev (-1) zero;
        elem = 0;
        next = next 1 zero;
    }) in
    zero
```

## Zadanie 6
```ocaml=
type 'a my_lazy = 'a lazy_node ref and
 'a lazy_node =
| Value of 'a
| Delayed of (unit -> 'a)
| Calc

let rec force m_lazy = match !m_lazy with
| Calc -> failwith "Calculating"
| Value a -> a
| Delayed f ->
    m_lazy := Calc;
    let calcval = f () in
    m_lazy := Value(calcval);
    calcval

let rec fix f = ref (Delayed(fun () -> f (fix f)))
```

## Zadanie 7

```ocaml=

type 'a info = 
| Cont of (unit -> 'a)
| Data of 'a
| Calculated

type 'a my_lazy =  'a info ref


let force mlz = 
  match mlz.contents with
  | Cont(f)    -> mlz := Calculated; let x = f () in mlz := Data(x); x
  | Data(d)    -> d
  | Calculated -> failwith "ERROR"

let fix f =
  let rec mlz =  
    ref (Cont(fun () -> f mlz))
  in mlz


type 'a llist = 
  'a node my_lazy

and  'a node = 
| Nil
| Cons of 'a * 'a llist

let rec of_list lst = fix (fun _ -> 
  match lst with
  | []     -> Nil
  | h :: t -> Cons(h, of_list t)
  )

let rec to_list llst = 
  match force llst with
  | Nil        -> []
  | Cons(h, t) -> h :: to_list t

let rec filter p llst = fix (fun _ -> 
  match force llst with 
  | Nil                 -> Nil
  | Cons(h, t) when p h -> Cons(h, filter p t)
  | Cons(_, t)          -> force (filter p t)
  )

let rec take_while p llst = fix (fun _ -> 
  match force llst with
  | Nil                 -> Nil
  | Cons(h, t) when p h -> Cons(h, take_while p t)
  | Cons(_, t)          -> Nil
  )

let rec for_all p llst = 
  match force llst with
  | Nil        -> true
  | Cons(h, t) -> p h && for_all p t

let rec nth n llst = 
  match n, force llst with 
  | _, Nil        -> failwith "Error"
  | 0, Cons(h, _) -> h
  | _, Cons(_, t) -> nth (n-1) t

let rec nats_from n = 
  fix (fun _ -> Cons(n, nats_from (n+1)))

let is_prime n = 
  (nats_from 2)
  |> take_while (fun p -> p * p <= n)
  |> for_all (fun p -> n mod p <> 0)

let rec primes = 
  fix (fun _ -> Cons(2, filter is_prime (nats_from 3)))



```

## Zadania 8 - 10

```ocaml=

(* Zadania 8, 10*)
type _ fin_type =
| Unit : unit fin_type
| Bool : bool fin_type
| Pair : 'a fin_type * 'b fin_type -> ('a * 'b) fin_type
| Fun : 'a fin_type * 'b fin_type -> ('a -> 'b) fin_type

let unit_seq = Seq.cons () Seq.empty
let bool_seq = Seq.cons true (Seq.cons false  Seq.empty)


let make_values domain codomain =
  let empty_fun = Seq.cons [] Seq.empty in
  Seq.fold_left (fun acc d -> 
  let pairs = Seq.map (fun cd -> (d, cd)) codomain in (* wszytkie pary true -> 'b *)
    Seq.flat_map (fun f -> Seq.map (fun pair -> pair :: f) pairs) acc
  ) empty_fun domain


let rec all_values:type a. a fin_type -> a Seq.t = function
| Unit -> unit_seq
| Bool -> bool_seq
| Pair(l, r) ->
  let ls, rs = all_values l, all_values r in
  Seq.flat_map (fun l -> Seq.map (fun r -> (l,r)) rs) ls
| Fun(a,b) ->
  let domain = all_values a
  and codomain = all_values b
  and list_to_fun flist = 
    (fun arg1 -> List.find (fun (arg2, v) -> equal_at a arg1 arg2) flist |> snd) in
  let all_functions = make_values domain codomain in
  Seq.map list_to_fun all_functions

and equal_at: type a. a fin_type -> a -> a -> bool  =
  function
  | Unit -> fun x y -> true
  | Bool -> fun x y -> x = y
  | Pair(_,_) -> fun (a,b) (c,d) -> a = c && b = d
  | Fun(a,b) ->
    fun f1 f2 -> 
      Seq.fold_left (fun all arg -> all && equal_at b (f1 arg) (f2 arg))
      true (all_values a)


(* Zadanie 9 *)
type empty = |

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


let unit_seq = Seq.cons () Seq.empty
let bool_seq = Seq.cons true (Seq.cons false  Seq.empty)

let rec all_values:type a. a fin_type -> a Seq.t = function
| Empty -> Seq.empty
| Unit -> unit_seq
| Bool -> bool_seq
| Either(l,r) ->
  let ls = all_values l |> Seq.map Either.left
  and rs = all_values r |> Seq.map Either.right
in Seq.append ls rs
| Pair(l, r) ->
  let ls, rs = all_values l, all_values r in
  Seq.flat_map (fun l -> Seq.map (fun r -> (l,r)) rs) ls

```

# Lista 5

# Lista 7

## Zadanie 1 & 2

```ocaml=


module RS : sig
  type 'a t
  val return : 'a -> 'a t
  val bind : 'a t -> ('a -> 'b t) -> 'b t
  val random : int t
  val run : int -> 'a t -> 'a
end = struct
  type 'a t = int -> 'a * int

  let return x s = (x, s) 

  let bind m f s = 
    let (x, s) = m s in
      f x s

  let hash a = 
    let b = (16807 * (a mod 127773)) - 2836 * (a mod 127773) in
    if b > 0 then b else b + 2147483647

  let random s = (s, hash s) 

  let run s m = let (x, _) = m s in x
end

let (let* ) = RS.bind

let rec rand n acc = 
  if(n = 0) 
    then RS.return acc
    else let* el = RS.random in
      rand (n - 1) (el :: acc)

let arr x = RS.run 0 (rand x [])


let shuffle s xs =
  let rec pick n = function
    | x :: xs ->
      if n = 0 
        then (x, xs) 
        else let (v, xs) = pick (n - 1) xs in
          (v, x :: xs)
    | _ -> failwith "error" 
  in
  let rec iter n acc xs = 
    if n = 0 
      then RS.return acc
      else 
        let* p = RS.random in
        let (v, xs) = pick (p mod n) xs in
        iter (n - 1) (v :: acc) xs
  in RS.run 
    s
    (iter (List.length xs) [] xs)

let shuffled1 = shuffle 1 [1; 2; 3; 4; 5]
let shuffled2 = shuffle 2 [1; 2; 3; 4; 5]
let shuffled3 = shuffle 3 [1; 2; 3; 4; 5]
let shuffled4 = shuffle 4 [1; 2; 3; 4; 5]
let shuffled5 = shuffle 5 [1; 2; 3; 4; 5]

``` 


## Zad3

```ocaml=
(* identity monad *)
module IM : sig
  type 'a t
  val return : 'a -> 'a t
  val bind : 'a t -> ('a -> 'b t) -> 'b t
  val test : 'a t -> 'a
end = struct

  type 'a t = 'a

  let return x = x

  let bind m f = f m
  
  let test m = m
end

(* testy *)

let x = IM.return 5;;
IM.test x;;

let (let*) = IM.bind;;

let rec test xl =
  match xl with
  | x :: xs ->
    let* a = IM.return x in
    let* b = (test xs) in
    IM.return (a :: b)
  | [] -> IM.return []
;;

let x = test [1;2;3];;
x;;
IM.test x;;


(* lazy monad *)

module LM : sig
  type 'a t
  val return : 'a -> 'a t
  val bind :  'a t -> ('a -> 'b t) -> 'b t
  val test : 'a t -> 'a
end = struct

  type 'a t = unit -> 'a

  let return x = fun () -> x

  let bind m f = f (m ())
  
  let test m = m ();;
end

(* testy *)
let rec r f x = f x;;

let lm = LM.return (r (fun x -> x * 2) 5);;

LM.test lm;;

let x = fun () -> 1;;
let f y = fun () -> y + 1;;
let g z = fun () -> z * 2;;

let (let*) = LM.bind;;

let x = test [1;2;3];;
x;;
IM.test x;;
```





## Zadanie 4

```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 : 'r.('a -> 'r ans) -> 'r ans }
  let return x = { run = fun k -> k x }
  let bind m f = { run = fun k -> m.run (fun a -> (f a).run k) }
  let fail = { run = fun _ -> None }
  let catch m f = { run = fun k -> 
    match m.run Option.some with
    | Some a -> (k a)
    | None -> (f ()).run k
  }

  let run x = x.run Option.some
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 : 'r. ('a -> 'r ans) -> 'r ans }
  let return x = { run = fun k -> k x }
  let bind m f = { run = fun k -> m.run (fun a -> (f a).run k)  }
  let fail = { run = fun _ -> Seq.empty }
  let flip = { run = fun k -> Seq.append (k true) (k false) }
  let run a = a.run Seq.return
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 'r ans = State.t -> 'r
  type 'a t = { run : 'r. ('a -> 'r ans) -> 'r ans }
  let return x = { run = fun k -> k x }
  let bind m f = { run = fun k -> m.run (fun a -> (f a).run k)  }
  let get = { run = fun k s -> k s s }
  let set s = { run = fun k _ -> k () s }
  let run s m = m.run (fun a -> fun _ -> a) s
end
```

## Zadanie 5
```=ocaml
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 (let* ) = BT.bind

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)

let rec match_regexpr : 'a regexp -> 'a list -> 'a list option BT.t =
  fun regexp prefix ->
    match regexp, prefix with
    | Eps, _ -> BT.return None
    | Lit p, c :: xs when p c -> BT.return (Some xs)
    | Or(a,b), _ ->
      let* c = BT.flip in
      if c then match_regexpr a prefix
      else match_regexpr b prefix
    | Cat(a,b), _ ->
      let* res1 = match_regexpr a prefix in
      (match res1 with
      | None -> match_regexpr b prefix
      | Some prefix -> 
        let* res2 = match_regexpr b prefix in 
        match res2 with 
        | None -> BT.return (Some prefix)
        | Some prefix -> BT.return (Some prefix)) 
    | Star a, _ -> 
      let* c = BT.flip in
      if not c then BT.return None
      else let* res1 = match_regexpr a prefix in
      (match res1 with
      | None -> BT.return None
      | Some prefix -> 
        let* res2 = match_regexpr regexp prefix in
        match res2 with
        | None -> BT.return (Some prefix)
        | Some prefix -> BT.return (Some prefix)
      ) 
    | _, _ -> BT.fail

```

## 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  *)



module SBT(State : sig type t end) = struct 
  type 'a t = State.t -> ('a * State.t) Seq.t
  
  let return: 'a -> 'a t = 
    fun x s -> Seq.return (x, s)

  let bind: 'a t -> ('a -> 'b t) -> 'b t =
    fun m f s ->
      let xs = m s in
        Seq.flat_map (fun (x, s) -> f x s) xs
  
  let fail : 'a t =
    fun s -> Seq.empty

  let flip : bool t =
    fun s -> List.to_seq [(true, s); (false, s)]

  let get : State.t t =
    fun s -> Seq.return (s, s)

  let put : State.t -> unit t =
    fun s _ -> Seq.return ((), s)

  let run : State.t -> 'a t -> 'a Seq.t = 
    fun s m -> 
      let xs = (m s) in 
      Seq.map (fst) xs
end
module Match(State : sig type t end) = struct
  module M = SBT(struct type t = State.t list end)
  let ( let* ) = M.bind

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 rec match_regexpr : 'a regexp -> 'a list M.t =
  fun regexp ->
    match regexp with
    | Eps -> M.return []
    | Lit p ->
      let* word = M.get in
      (match word with
      | [] -> M.fail
      | x :: xs when p x ->
        let* () = M.put xs in
        M.return [x]
      | _ -> M.fail)
    | Or(a,b) ->
      let* c = M.flip in
      if c then match_regexpr a
      else match_regexpr b 
    | Cat(a,b) ->
      let* res1 = match_regexpr a in
      let* res2 = match_regexpr b in
      M.return (res1 @ res2)
    | Star a -> 
      let* c = M.flip in
      if not c then M.return []
      else let* res1 = match_regexpr a  in
      (match res1 with
      | [] -> M.return []
      | _ -> 
        let* res2 = match_regexpr regexp in
        M.return (res1 @ res2)
        ) 
    | _ -> M.fail
end

```


## Zadanie 7 

:::warning
  Częściowo niegotowe
  DaBi: poprawna funkcja bind poniżej
:::

```ocaml=


module SBTR(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 set : State.t -> unit t

  val run : State.t -> 'a t -> 'a Seq.t

end = struct
  
  type 'a t = State.t -> 'a sbt_list
  and 'a sbt_list =
  | Nil
  | Cons of 'a * State.t * 'a t

  let return x s = Cons(x, s, fun s -> Nil)

  (* a t -> ('a -> 'b t) -> 'b t *)
  (*  Seq.flat_map (fun (v, s) -> f v s) (m s) *)
  let rec bind :'a t -> ('a -> 'b t) -> 'b t = 
     (*  fun x -> failwith "TODO" *)
    
    fun m f s ->
    let rec concat xs ys =
      match xs with
      | Cons(v, s, xs) -> (fun s -> Cons(v, s, concat (xs s) ys))
      | Nil -> (fun s -> ys)
    in
    let rec map = function
      | Cons(v, s, xs) -> (*concat*) (f v) (* (xs s) *)
      | Nil -> (fun s -> Nil)
    in (map (m s)) s
  
  (* let rec bind m f = Seq.flat_map f m *)
  (* let bind m f s =
    let (x, s) = m s in
    f x s *)

  let fail :'a t = 
    fun s -> Nil
  let flip : bool t = 
    fun s -> Cons(true, s, fun s -> Cons(false, s, fun s -> Nil))

  let get : State.t t =
    fun s -> Cons(s, s, fun s -> Nil)
  let set : State.t -> unit t =
    fun s _ -> Cons((), s, fun s -> Nil)

  let run : State.t -> 'a t -> 'a Seq.t = 
    let rec map = function
    | Nil -> Seq.empty
    | Cons(v, s, tl) ->
      Seq.cons v (map (tl s))
    in
    fun s m -> 
      m s |> map
end

module N = SBTR(Int)

let id x = 
  let h x =
    N.return x
  in N.run 0 (h x)


  let (let* ) = N.bind

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


let rec arrs n acc =
  if n = 0 
  then N.return acc 
  else let* c = N.flip in
    let* v = N.get in
    let* () = N.set (v + 1) in
      if c  then (arrs (n - 1) (v :: acc))
            else (arrs (n - 1) acc)

let force_all m = 
  let rec iter m xs =
    match Seq.uncons m with
    | Some(a, b) -> iter b (a :: xs)
    | None -> xs
  in
  iter m []

  let subs = arrs 3 [] |> N.run 1 |> force_all

```
:::info
Poprawiona funkcja bind.

Funkcja concat nie łączy list, ale drzewa (obiekty typu 'a t) 
:::
```ocaml=
 let rec bind m f = 
   let rec concat m1 m2 =
     fun s ->
     match m1 s with
     | Nil -> m2 s
     | Cons(v, s', m2') -> Cons(v, s', concat m2' m2)
   in
   let rec map = function
     | Nil -> Nil
     | Cons(v, s, m') -> concat (f v) (fun s' -> map (m' s')) s
   in fun s -> map (m s)
```

---
# Lista 8

## Zadanie 3 
```haskell=
listTrans :: StreamTrans i o a -> [i] -> ([o], a)
listTrans (Return x) xs =
  ([], x)
listTrans (ReadS f) xs =
  listTrans (f hd) tl
  where
    hd = case xs of
      [] -> Nothing
      (h : _) -> Just h
    tl = case xs of
      [] -> []
      (_ : t) -> t
listTrans (WriteS o st) xs =
  let (rs, x) = listTrans st xs
   in (o : rs, x)
```

## Zadanie 5

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

(|>|) :: StreamTrans i m a -> StreamTrans m o b -> StreamTrans i o b
_ |>| (Return b) = Return b
s1 |>| (WriteS o s2) = WriteS o (s1 |>| s2)
(ReadS c1) |>| s2 = ReadS (\mi -> c1 mi |>| s2)
(WriteS m s1) |>| (ReadS c2) = s1 |>| c2 (Just m)
s1 |>| (ReadS c2) = s1 |>| c2 Nothing
```


## Zadanie 6
```haskell=
reverseList xs = foldl (\x y -> y:x) [] xs 

catchOutput :: StreamTrans i o a -> StreamTrans i b (a, [o])
catchOutput s = helper s []
  where
    helper (Return a) os = Return (a, (reverseList os))
    helper (ReadS c) os = ReadS (\x -> helper (c x) os)
    helper (WriteS o s) os = helper s (o:os)

--listRun służy do uruchomienia StreamTrans z listą wejściową i zasymulowania wypisywania na output
listRun :: StreamTrans Char Char a -> [Char] -> a
listRun (ReadS f) [] = (listRun (f Nothing) [])
listRun (ReadS f) (x:xs) = listRun (f (Just x)) xs
listRun (WriteS y trans') xs = listRun trans' xs
listRun (Return a) xs = a


main::IO()
main = putStrLn (snd (listRun (catchOutput toLower) "ASbs"))

```


## Zadanie 8
```haskell=
type Tape = ([Integer], [Integer])
emptyTape = (repeat 0, repeat 0)

runBF :: [BF] -> StreamTrans Char Char () 
runBF code = 
    evalBFBlock emptyTape code >>= (\ tape -> Return ())
    
evalBF :: Tape -> BF -> StreamTrans Char Char Tape
evalBF (prev, h : t) MoveR = 
    Return (h : prev, t)

evalBF (h : t, next) MoveL = 
    Return (t, h : next)

evalBF (prev, h : t) Inc = 
    Return (prev, (h+1) : t)

evalBF (prev, h : t) Dec = 
    Return (prev, (h-1) : t)

evalBF (prev, h : t) Input = 
    ReadS (\ (Just c) -> Return (prev, charToInt c : t))

evalBF tape@(prev, h : t) Output = 
    WriteS (intToChar h) (Return tape)

evalBF tape@(prev, h : t) (While xs) =
    if h > 0 
        then evalBFBlock tape xs >>= (\ t -> evalBF t (While xs))
        else Return tape

-- dwa przypadki, które nie zachodzą, ponieważ listy są nieskończone
evalBF ([], next) MoveL = 
    Return ([], next)

evalBF (prev, []) bf = 
    Return (prev, [])
-- 

evalBFBlock :: Tape -> [BF] -> StreamTrans Char Char Tape
evalBFBlock = 
    foldM evalBF
    
coerceEnum :: (Enum a, Enum b) => a -> b
coerceEnum = toEnum . fromEnum

charToInt :: Char -> Integer
charToInt c = 
    coerceEnum c - 48

intToChar :: Integer -> Char
intToChar n = 
    coerceEnum (n + 48)
    
```

## Zadanie 9
```haskell=
instance Functor (StreamTrans i o) where
  fmap f m = m >>= return . f

instance Applicative (StreamTrans i o) where
  pure = return
  (<*>) = ap

instance Monad (StreamTrans i o) where
  return a = Return a

  (>>=) (Return a) f =
    f a
  (>>=) (ReadS func) f =
    ReadS (\c -> func c >>= f)
  (>>=) (WriteS o m) f =
    WriteS o m >>= f
```