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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
open StdLabels
module M(T:Sounds.T) = struct
type voyel = (T.t * T.t )
type consonants =
{ ending : T.t option option
; opening : T.t list
; following : T.t option }
type group = voyel * consonants option
type modifier = (group * T.t option option) -> (group * T.t option option)
(** Apply all the modifiers to the syllabic group in order to correct the
relation between the elements
This is just a fold_left list, and the order matter : for example
nasalisation shall be applied after the S vocalisation
*)
let apply_modifiers
: group * T.t option option -> modifier list -> group * T.t option option
= fun e m ->
List.fold_left m
~init:e
~f:(fun e f -> f e)
(** The Nasal modifier transform a voyel followed by N and a consonant
into a nasal voyel.
Does this min that nasal voyel are not a distinct element, but just a
merge from two distinct elements ? *)
let nasal
: modifier
= fun init ->
let (((v1, v2), c) , ending) = init in
let ending = Option.bind ending (fun x -> x) in
match ending with
| None -> init
| Some ending ->
match T.is_nasal ending with
| false -> init
| true ->
(* Remove the ending consonant, and transform the voyel into
the nasal form *)
( ( (T.nasal v1, T.nasal v2)
, c )
, None )
(** Transform the S into Z if the S is the opening consonant and
there is no ending consonant before *)
let vocalize_s
: modifier
= fun init ->
let (((v1, v2), c) , ending) = init in
match c with
| None -> init
| Some op ->
(* The voyel may be none in case of ending word. In such case, we shall
not trnasform the S into Z *)
let is_voyel = T.is_voyel v1 && T.is_voyel v2 in
match is_voyel, op.opening, op.ending with
| true, hd::[], None when T.code hd = T.SZ ->
let c = Some { op with opening = [T.z ()] } in
(((v1, v2), c) , ending)
| _ -> init
(** Mute the last consonant if there is no voyel in the syllabus.
This modifier is only applied in the first step, and not repeated anymore.
*)
let mute_consonant
: modifier
= fun init ->
let (((v1, v2), c) , ending) = init in
let is_voyel = T.is_voyel v1 && T.is_voyel v2 in
match is_voyel, c with
| false, Some c ->
let c = { c with opening = List.map ~f:T.muted c.opening } in
(((v1, v2), Some c) , ending)
| _ -> init
let change_voyel
= fun init ->
let (((v1, v2), _) , ending) = init in
match ending with
| None -> v2
| Some _ -> v1
let rec _rebuild ~(m:modifier list) acc ending_consonant : group list -> T.t list
= function
| [] -> acc
| hd::tl ->
let modifier = vocalize_s :: nasal :: m in
let (voyel, consonants), ending_consonant =
apply_modifiers
(hd, ending_consonant)
modifier in
let voyel = change_voyel ((voyel, consonants), ending_consonant) in
(* Add the last consonant and the voyel *)
let m, acc = match ending_consonant with
| None -> modifier, voyel::acc
| Some s ->
let default = modifier, voyel :: acc in
match s with
| None -> default
| Some s ->
modifier, voyel :: s::acc in
match consonants with
| None -> _rebuild ~m acc None tl
| Some {ending; opening; following} ->
let acc = match following with
| None -> acc
| Some s -> s::acc in
match opening with
| [] ->_rebuild ~m acc ending tl
| opening -> _rebuild ~m (opening @ acc) ending tl
(** Rebuild the list in the normal order
The voyels have to be choosen, depending either they are followed by a
consonant or not
Some consonants may be changed depending of the following voyel
The list has to be reversed
and so one
*)
let rebuild
: consonants option -> group list -> T.t list
= fun ending elems ->
let elems' = match ending with
| None -> elems
| Some _ -> ((T.none, T.none), ending)::elems in
_rebuild ~m:[mute_consonant] [] None elems'
end
|