1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  | #!/usr/bin/env fsharpi
(* This construct is for ML compatibility. The syntax '(typ,...,typ) ident'
   is not used in F# code. Consider using 'ident<typ,...,typ>' instead. *)
#nowarn "62"
[<RequireQualifiedAccess>]
module Huffman =
  type tree =
    | Leaf of frecuency * char
    | Node of frecuency * tree * tree
  and frecuency = int
  
  let frecuency : tree -> frecuency * tree = function
    | Leaf (f,_)   as t -> f,t
    | Node (f,_,_) as t -> f,t
  
  let encoding : string -> tree =
    fun text ->
      let rec aux : tree Set -> tree =
        fun acc0 ->
          if Set.isEmpty acc0 then
            failwith "Set is empty"
          else if Set.count acc0 = 1 then
            Set.minElement acc0
          else
            let (f1,x) = acc0 |> Set.minElement |> frecuency
            let (acc1) = acc0 |> Set.remove x
            let (f2,y) = acc1 |> Set.minElement |> frecuency
            let (acc2) = acc1 |> Set.remove y
            
            acc2 |> Set.add (Node (f1+f2,x,y))  |> aux
      text
      |> Seq.groupBy id
      |> Seq.map (fun (x,xs) -> xs |> Seq.length,x)
      |> Set.ofSeq
      |> Set.map Leaf
      |> aux
  
  let tree2charmap : tree -> (char, int list) Map =
    fun t ->
      let rec aux acc : tree -> (char, int list) Map = function
        | Leaf (_,c)   -> Map.empty |> Map.add c (List.rev acc)
        | Node (_,l,r) ->
          let ml = aux (0::acc) l
          let mr = aux (1::acc) r
          ml |> Map.fold(fun a k v -> a |> Map.add k v) mr
      aux [] t
  
  let table : (char, int list) Map -> string =
    fun map ->
      map
      |> Map.toList
      |> List.map (fun (k,v) -> sprintf "'%c': %A\n" k v)
      |> List.fold (fun a x -> a + x) ""
  
  let tree2codemap : tree -> (int list, char) Map =
    fun t ->
      let rec aux acc : tree -> (int list, char) Map = function
        | Leaf (_,c)   -> Map.empty |> Map.add (List.rev acc) c
        | Node (_,l,r) ->
          let ml = aux (0::acc) l
          let mr = aux (1::acc) r
          ml |> Map.fold(fun a k v -> a |> Map.add k v) mr
      aux [] t
  
  let compress : (char, int list) Map -> string -> string =
    fun map text ->
      text
      |> Seq.map (fun c -> map |> Map.find c)
      |> Seq.collect id
      |> Seq.fold (fun a x -> a + (string x)) ""
  
  let decompress : (int list, char) Map -> string -> string =
    fun map code ->
      let rec aux acc code = function
        | [     ] -> acc |> List.rev
        | x :: xs ->
          let code'       = code @ [x]
          let copt        = map |> Map.tryFind code'
          let acc',code'' =
            match copt with
              | Some c -> c::acc, [   ]
              | None   ->    acc, code'
          aux acc' code'' xs
      let xs = code |> Seq.map (string >> int) |> Seq.toList
      aux [] [] xs |> List.fold (fun a x -> a + (string x)) ""
 |