Последовательность, как она определена, не имеет функции клона только потому, что она «определена по умолчанию».
type 'a node =
| Nil
| Cons of 'a * 'a t
and 'a t = unit -> 'a node
Как вы можете видеть, это просто функция, возвращающая некоторый тип суммы, простое значение, еслиВы хотите, нет никаких побочных эффектов (на самом деле они могут быть скрыты в теле функции, но сейчас позвольте мне обмануть вас).Таким образом, функция клона в этом случае является просто тождеством:
let clone s = s
Теперь, если вы посмотрите на определение перечисления, вы заметите небольшое ключевое слово mutable
:
type 'a t = {
mutable count : unit -> int;
mutable next : unit -> 'a;
mutable clone : unit -> 'a t;
mutable fast : bool;
}
Если мыпопробуйте использовать тот же clone
, что и для последовательностей, мы заметим, что изменения одной копии будут влиять на другую:
# let e1 = { fast = true; (* ... *) };;
val e1 : 'a t = {fast = true; (* ... *)}
# let e2 = clone e1;;
val e2 : 'a t = {fast = true; (* ... *)}
# e1.fast <- false;;
- : unit = ()
# e2;;
'a t = {fast = false; (* ... *)}
Вот почему им нужна функция clone
.
Тактеперь вы можете реализовать свои функции, например prefix_action
.
prefix_action f e
будет вести себя как e
, но гарантирует, что f ()
будет вызван ровно один раз перед текущим первым элементом e
читается.
Проблема в этом "ровно один раз" .Я не уверен, что это значит, но допустим, что это означает, что если вы передадите последовательность в prefix_action f
, а затем два раза в hd
, то f
будет выполнен только один раз (потому что если это означает что-то другоеэто не интересно).И теперь мы можем вернуться к этой истории «побочных эффектов».Ясно, что мы не можем реализовать prefix_action
без них.Тип последовательности не содержит ни одного ключевого слова mutable
, но содержит функции!Следовательно, мы можем включить наш побочный эффект в функцию.
let prefix_action : (unit -> unit) -> 'a t -> 'a t = fun f s ->
let b = ref true in
fun () -> (if !b then f (); b := false); s ()
Но теперь, когда у нас есть побочные эффекты, нам нужно переопределить clone
.Из спецификации prefix_action
:
Если клонируется prefix_action f e
, f
вызывается только один раз, во время клонирования.
Следовательно, наш clone
:
let clone s = let _ = s (); s