I want to merge two pattern matching functions


#1

Hello everyone!
As my title says, I am want to merge two pattern matching functions into one function. The purpose of my goal is to create a function that converts: char list -> string.

So I made two functions:

let rec urejanje list = match list with
| [] -> []
| h::t -> Char.escaped h::urejanje t

let rec zdruzi list = match list with
| [] -> “”
| h::t -> h^zdruzi t

Now the first one’s input is char list ex.: [‘a’;‘b’;‘c’]. The first function converts char list into string list ex: [‘a’;‘b’;‘c’] -> [“a”;“b”;“c”]
Then the second function kicks in where input is result of first function: ex: [“a”;“b”;“c”]. The second function converts string list into string ex: [“a”;“b”;“c”] ->“abc”.

what I would like to do is somehow merge this two functions into one function.
I hope I made it clear what I want.
Regards
F


#2

If only to satisfy the overall goal, then you can do

let f (l : char list) : string =
  String.concat "" (List.map Char.escaped l)

If it must look like the original ones, then you can do

let f (l : char list) : string =
  let rec aux (l : char list) (acc : string) : string =
    match l with
    | [] -> acc
    | x :: xs -> aux xs (acc ^ (Char.escaped x))
  in
  aux l ""

Note that it might not be very efficient.


#3

Thank you very much for reply!
what does it mean (l:char list) : string?
that input l is of type char list but what about that string then?


#4

That’s just the function’s return type.


#5

Ohh okay… so there is still just input l which is char list. got it! thank you very much!
But why do you have to declare that?
Best of regards
F


#6

Just purely habit and personal preference.

I tend to do this just so I can spot the type immediately, which is quite important when you’re dealing with a lot of code.

Some people prefer only leaving type signatures in .mli files and so on.


#8
(* Version 1. *)

let rec escape_1 = function
  | [] -> []
  | c :: cs -> Char.escaped c :: escape_1 cs

let rec join_strings_1 = function
  | [] -> ""
  | c :: cs -> c ^ join_strings_1 cs

let join_1 cs =
  (* Traverses the list twice. *)
  join_strings_1 (escape_1 cs)

(* Version 2.

   A generalization of [escape]. Still two traversals. *)

let rec map f = function
  | [] -> []
  | c :: cs -> f c :: map f cs

let join_2 cs =
  join_strings_1 (map Char.escaped cs)

(* Version 3.

   Now only one traversal, but manual looping. *)

let rec join_3 = function
  | [] -> ""
  | c :: cs -> Char.escaped c ^ join_3 cs

(* Version 4.

   Just for fun.

   Define a lazy list, like Haskell.

   Now, we can "save up" multiple transformations, and only traverse the list once at the end. *)

module Lazy_list = struct
  let ( !! ) = Lazy.force

  type 'a t =
    | Nil
    | Cons of 'a Lazy.t * 'a t Lazy.t

  let items xs =
    List.fold_right (fun x xs -> Cons (lazy x, lazy xs)) xs Nil

  let fold_left z f t =
    let rec loop acc = function
      | Nil -> acc
      | Cons (lazy x, lxs) -> loop (f acc x) !!lxs
    in

    loop z t

  let rec map f = function
    | Nil -> Nil
    | Cons (lazy x, lxs) -> Cons (lazy (f x), lazy (map f !!lxs))
end

let join_4 cs =
  Lazy_list.items cs
  |> Lazy_list.map Char.escaped
  |> Lazy_list.fold_left "" (fun ss s -> ss ^ s)


#9

Thank you very much for replying me. This lazy list looks long :S