Что является аналогом OCaml для «с» -стамента Python (автоматическое освобождение ресурсов) - PullRequest
0 голосов
/ 11 июня 2018

Что является аналогом OCaml для "with" -статмента Python?

with open('test.txt', 'r') as f:
    # Do stuff with f
# At this point, f will always be closed, even in case of exceptions

То есть: Что является предпочтительным способом в OCaml для безопасного обеспечения того, что определенный ресурс (открытыйфайл, соединение с базой данных, HTTP-соединение и т. д.) всегда будут освобождены в определенный момент времени?Ожидание сборщика мусора здесь не вариант, и исключения никогда не должны препятствовать освобождению ресурсов.

Конечно, в OCaml вы всегда можете использовать try-finally и закрыть файл «вручную», как вы можетесделать в Python.Однако такой код подвержен ошибкам.Вот почему Python ввел выражение «с».Какова идиома OCaml, чтобы сделать этот вид кода более легким для чтения и менее подверженным ошибкам?

Обратите внимание, что этот вопрос сильно отличается от вопроса Эмуляция try-with-finally в OCaml ,так как это еще один шаг вперед: я не просто хочу эмулировать try-finally в OCaml!(кстати, Lwt [%finally ...] отлично справляется с работой.) Я хочу сделать еще один шаг вперед, избавляя от необходимости писать эти предложения finally во-первых - как это можно сделать в Python.

Также обратите внимание, что этот вопрос не о деталях реализации , а об идиомах : какой из всех возможных проектов и решений получил некоторую популярность в сообществе OCaml и являетсяобщепринятый?

Ответы [ 4 ]

0 голосов
/ 12 июня 2018

Еще одна простая реализация.

Давайте сначала определим тип, представляющий либо результат, либо исключение:

type 'a okko = Ok of 'a | Ko of exn

Затем определим capture_errors:

let capture_errors fn = try Ok (fn ()) with e -> (Ko e);;

Вы можете их реализовать unwind_protect:

let unwind_protect wind unwind =
  let result = (capture_errors wind) in
  begin
    unwind ();
    match result with
    | Ok (result) -> result
    | Ko (error) -> raise error
  end;;

Выше последовательно последовательно выполните unwind один раз.

Затем вы можете определить общую функцию with_:

let with_ enter leave body =
    let e = enter() in
    unwind_protect
      (fun () -> (body e))
      (fun () -> (leave e)) ;;

Например, with_open_file может быть определено как:

let with_open_file opener closer file fn =
  with_
    (fun () -> (opener file))
    (fun (chan) -> (closer chan))
    fn

Вы можете карри open_in и close_in в общем случае:

let with_input_file = with_open_file open_in close_in;;

Дляпример:

with_input "/etc/passwd" input_line
0 голосов
/ 11 июня 2018

Здесь есть несколько разумных ответов (эмуляция try with finally в ocaml) , хотя отсутствие макросов делает его несколько более громоздким, чем в противном случае (см., Например, эту жалобу под "Нет макросов")

0 голосов
/ 12 июня 2018

Замена стандартной библиотеки JaneStreet core_kernel обеспечивает именно то, что вам нужно, в виде In_channel.with_file.Так что, если случайно вы используете core_kernel, посмотрите примеры использования здесь: https://dev.realworldocaml.org/imperative-programming.html#file-io

0 голосов
/ 11 июня 2018

"with" в python использует специальные объекты, которые управляют ресурсами и имеют функцию очистки, которая вызывается, когда завершается "with".У Окамла такого нет.Но вы можете их реализовать.

Что-то вроде:

let with_ (constructor, destructor) fn =
   let obj = constructor () in
   try
       let res = fn obj in
       destructor obj;
       res
   with exn ->
       destructor obj;
       raise exn

Или использовать объект ocaml, у которого есть метод уничтожения.ваши пункты finally в методе деструктора или уничтожения, поэтому вам не нужно писать его вручную.

...