OCaml: Как построить отформатированную строку в стиле Python? - PullRequest
2 голосов
/ 02 ноября 2009

Все это начинается с простой идеи: как написать отформатированную строку в стиле python в ocaml.

pythoners может начать строку как:

str = "this var: %s" % this_var
str2 = "this: %s; that: %s" % (this_var, that_var)

но форматированный строковый код ocaml как:

let str = Printf.sprintf "this var: %s" this_var
let str2 = Printf.sprintf "this: %s; that: %s" this_var that_var

Я верил, что смогу сделать что-то, чтобы строка ocaml форматировала код как Python Сначала я определил функцию следующим образом:

let (%) s x = Printf.sprintf s x

тогда я могу написать прямо как:

let str = "this: %s" % "sth"

но простая функция не может обрабатывать более сложные ситуации как две или более переменных. поэтому я хотел написать небольшую сложную функцию, чтобы она идеально имитировала путь Python. Я написал это как ниже:

let (%) s li = 
  let split_list = Str.full_split (regexp "%[a-z]") s in
  let rec fmt result_str s_list x_list = match s_list with
    | [] -> result_str
    | shd::stl -> match shd with
       | Text t ->  fmt (result_str^t) stl x_list
       | Delim d -> match x_list with
          | [] -> fmt result_str stl []
          | xhd::xtl -> fmt (result_str^(Printf.sprintf d xhd)) stl xtl
  in 
  fmt "" split_list li

Но функция просто НЕ МОЖЕТ работать, потому что ошибка типа, а также список ocaml не могут содержать несколько типов. если вы напишите что-то вроде: "name: %s; age: %d" % ["John"; 20] мир компиляторов ocaml рассмеется над кодом и скажет вам что-то типа ERROR.

Очевидно, я должен использовать Tuple для замены List. но я просто НЕ знаю, как выполнить хвостовую рекурсию кортежа переменной длины.

приветствуется любое предложение. У меня действительно два вопроса.

  1. как написать код python для ocaml для форматирования строки.
  2. Если Ocaml не может динамически генерировать какую-либо строку в формате format6 str и передать его в sprintf? для кода:

    let s = "% s" в Printf.sprintf s "привет"

    сгенерирует информацию об ОШИБКЕ как:

    Ошибка: это выражение имеет строку типа но ожидалось выражение типа ('a ->' b, единица измерения, строка) format = ('a ->' b, единица, строка, строка, строка, строка) format6

Ответы [ 5 ]

5 голосов
/ 02 ноября 2009

(1) Я не думаю, что есть хороший способ сделать это, который будет лучше, чем использование Printf.sprintf напрямую. Я имею в виду, вы можете расширить то, что вы уже придумали:

let (%) = Printf.sprintf
let str3 = ("this: %s; that: %s; other: %s" % this_var) that_var other_var

, который работает, но уродлив из-за скобок, которые необходимы для приоритета.

(2) Очень сложно сгенерировать строку формата во время выполнения, потому что строки формата анализируются во время компиляции. Они могут выглядеть как строковые литералы, но на самом деле это другой тип, который представляет собой «что-то формат6». (он определяет, хотите ли вы строку или строку формата на основе выведенного типа). Фактически, точный тип строки формата зависит от того, какие заполнители находятся в формате; это единственный способ проверить число и тип аргументов формата. Лучше не связываться со строками форматирования, потому что они очень сильно связаны с системой типов.

2 голосов
/ 03 ноября 2009

Почему нужно заменить статически проверенный sprintf динамическим форматированием? Printf от OCaml компактен в использовании и безопасен во время выполнения. Сравните это с C printf, который компактен, но небезопасен, и с потоками C ++, которые безопасны, но многословны. Формат Python ничуть не лучше, чем C printf (за исключением того, что вместо crashdump вы получаете исключение).

Единственный возможный вариант использования - это строка формата, поступающая из внешнего источника. И обычно лучше переместить его во время компиляции. Если это невозможно, то нужно только вернуться к ручному динамическому форматированию с обработкой ошибок (как уже говорилось, вы не можете использовать Printf со строкой динамического форматирования). Кстати, один такой случай - интернационализация - охватывается существующими библиотеками . Как правило, если требуется динамическое объединение нескольких значений разных типов, необходимо обернуть их вариантами (например, ['S "hello"; 'I 20]) и сопоставить с шаблоном на стороне печати. ​​

1 голос
/ 16 апреля 2018

Это действительно выполнимо, если ваш оператор начинает с символа #, поскольку этот символ имеет более высокий приоритет, чем приложение функции.

let (#%) = Printf.sprintf;;
val ( #% ) : ('a, unit, string) format -> 'a = <fun>
"Hello %s! Today's number is %d." #% "Pat" 42;;
- : string = "Hello Pat! Today's number is 42."
1 голос
/ 14 октября 2010

Вы должны проверить расширенные / расширяемые аккумуляторы OCaml printf. У меня такое чувство, что вы можете делать с ним все, что хотите.

0 голосов
/ 02 мая 2010

Если Ocaml не может генерировать динамически какая-то строка в формате format6 str и передать ее спринтф? для кода:

let s = "%s" in Printf.sprintf s "hello"

Что если мы обойдем систему ввода ...

external string_to_format :
 string -> ('a, 'b, 'c, 'd, 'e, 'f) format6 = "%identity"

let s = string_to_format "%s" in (Printf.sprintf s "hello" : string);;

Я не претендую на то, что это окончательное решение, но это то, что я получил после просмотра списка рассылки, http://pauillac.inria.fr/caml/FAQ/FAQ_EXPERT-eng.html#printf и источника ocaml.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...