Почему рациональные числа из Num печатаются как ‹abstr›?

Я продолжаю свое исследование библиотеки Num Ocaml по той причине, что с ее помощью была написана целая библиотека о логике.

Сегодня я хотел бы сделать отрицательное рациональное число. Получите -1/2 от 1/2.

Для этого я думаю, что, имея a типа Ratio.ratio, я могу вычислить его отрицательное значение (и вернуть ratio, а не num) следующим образом:

ratio_of_num (minus_num (num_of_ratio a))

(Функции из: https://ocaml.org/releases/4.05/htmlman/libref/Num.html#TYPEnum)

Теперь я хотел бы проверить результат, но я всегда получаю это решение: Ratio.ratio = <abstr>

Дело в том, что теперь я понимаю, что всегда получаю это решение, когда использую ratio_of_num. Например:

ratio_of_num (Int 2);;
- : Ratio.ratio = <abstr>

Я немного поискал и нашел этот вопрос (форматирование вывода верхнего уровня OCaml), где другая функция ( ratio_of_int 2) использовалось, но больше не представляется возможным. Возможно, что ratio — это другая библиотека.

Любая помощь?

PS: Кстати, чтобы в будущем заменить num, пытаюсь установить Zarith на opam, но не получается.

Моя проблема в том, что я делаю opam install zarith, и это отображается:

┌─ The following actions failed
│ λ build conf-gmp 3
└─ 
╶─ No changes have been performed

The packages you requested declare the following system dependencies. Please
make sure they are installed before retrying:
    gmp

Итак, я делаю opam install gmp и получаю:

┌─ The following actions failed
│ λ build gmp 6.2.1
└─ 
╶─ No changes have been performed

Что не дает мне никакого представления о том, как продолжать попытки. Любая помощь с этим тоже?

Буду признателен за любой ответ, будь то на первый вопрос или на второй!!

Здесь ниже я размещаю некоторые редакции, которые были добавлены к вопросу, в результате беседы ниже:

РЕДАКТИРОВАТЬ (решено добавлением необходимого #require)

Я сделал то, что предложил @ivg, но все равно не работает (я делаю начальный open Num, потому что он спросит иначе):


─( 23:12:59 )─< command 0 >──────────────────────────────────────{ counter: 0 }─
utop # open Num;;
─( 23:13:00 )─< command 1 >──────────────────────────────────────{ counter: 0 }─
utop # let pp_num ppf x = Format.fprintf ppf "%s" (Num.string_of_num x);;
val pp_num : Format.formatter -> num -> unit = <fun>
─( 23:14:11 )─< command 2 >──────────────────────────────────────{ counter: 0 }─
utop # #install_printer pp_num;;
─( 23:14:16 )─< command 3 >──────────────────────────────────────{ counter: 0 }─
utop # ratio_of_num (Int 2);;
- : Ratio.ratio = <abstr>

РЕДАКТИРОВАТЬ 2 (также требуется #require)

Я также пробовал Ocaml вместо utop, но ошибка хуже:

        OCaml version 4.10.2

Findlib has been successfully loaded. Additional directives:
  #require "package";;      to load a package
  #list;;                   to list the available packages
  #camlp4o;;                to load camlp4 (standard syntax)
  #camlp4r;;                to load camlp4 (revised syntax)
  #predicates "p,q,...";;   to set these predicates
  Topfind.reset();;         to force that packages will be reloaded
  #thread;;                 to enable threads

# open Num;;
# let pp_num ppf x = Format.fprintf ppf "%s" (Num.string_of_num x);;
Error: Reference to undefined global `Num'
# 

РЕДАКТИРОВАТЬ 3 (работает в Ocaml вместо utop)

##require "num";;
# let pp_num ppf x = Format.fprintf ppf "%s" (Num.string_of_num x);;
val pp_num : Format.formatter -> Num.num -> unit = <fun>
# #install_printer pp_num;;
# ratio_of_num (Int 2);;
- : Ratio.ratio = <ratio 2/1>
# 

РЕДАКТИРОВАТЬ 4 (работает в utop, обратите внимание, что печать упрощает результат, когда он является целым числом)

utop # let pp_ratio ppf r = Format.fprintf ppf "%a" pp_num (num_of_ratio r);;
val pp_ratio : Format.formatter -> Ratio.ratio -> unit = <fun>
─( 23:28:07 )─< command 6 >──────────────────────────────────────{ counter: 0 }─
utop # #install_printer pp_ratio;;
─( 23:28:22 )─< command 7 >──────────────────────────────────────{ counter: 0 }─
utop # ratio_of_num (Int 2);;
- : Ratio.ratio = 2
─( 23:28:29 )─< command 8 >──────────────────────────────────────{ counter: 0 }─
utop # 


person Theo Deep    schedule 12.05.2021    source источник
comment
Должен отметить, что это 6666-й вопрос с тегом [ocaml]. Поздравляю!   -  person Maëlan    schedule 13.05.2021
comment
Вау, спасибо! jejeje   -  person Theo Deep    schedule 13.05.2021


Ответы (1)


Причина, по которой у вас есть <abstr> вместо фактического представления, заключается в том, что верхний уровень (он же интерпретатор) не знает, как напечатать объект num. Легко обучить верхний уровень, используя директиву #install_printer, например,


let pp_num ppf x = Format.fprintf ppf "%s" (Num.string_of_num x);;
val pp_num : Format.formatter -> Num.num -> unit = <fun>
# #install_printer pp_num;;
# ratio_of_num (Int 2);;
- : Ratio.ratio = <ratio 2/1>
# 

Итак, мы определили функцию красивой печати,

let pp_num ppf x = Format.fprintf ppf "%s" (Num.string_of_num x)

А затем использовал директиву #install_printer для установки на верхнем уровне,

# #install_printer pp_num;;

и теперь каждый раз, когда у нас есть num, он будет печататься для нас.

Вы также можете использовать эту функцию pp_num вместе с другими функциями модуля Format (которые используются для красивой печати), например,

Format.printf "my num = %a" pp_num (ratio_of_num (Int 2))

Возможно, более старая версия OCaml не может определить, как печатать коэффициент из самих чисел, поэтому мы можем помочь ей, определив дополнительный принтер,

# let pp_ratio ppf r = Format.fprintf ppf "%a" pp_num (num_of_ratio r);;
val pp_ratio : Format.formatter -> Ratio.ratio -> unit = <fun>
# #install_printer pp_ratio;;
# ratio_of_num (Int 2);;
- : Ratio.ratio = 2

Re: P.S.

Для zarith вам необходимо установить системные зависимости. Для этого вы можете использовать opam, например,

opam depext --install zarith

он установит системные зависимости (библиотеку gmp) с помощью менеджера пакетов вашей операционной системы, а затем установит библиотеку zarith.

person ivg    schedule 12.05.2021
comment
Привет! Это имеет смысл, поэтому нужен красивый принтер. Дело в том, что я сделал то, что вы сказали, и проблема все еще остается. Я делаю то же самое, а затем (посмотрите мой РЕДАКТИРОВАТЬ на начальный вопрос). - person Theo Deep; 13.05.2021
comment
странно, можно попробовать ocaml вместо utop? Также может быть, что ваш OCaml очень старый... какую версию вы используете? - person ivg; 13.05.2021
comment
Если я сделаю это в Ocaml, вы увидите ответ в EDIT2. Я тоже спрашиваю which ocaml и отвечаю 4.10.2 так что... (кстати, я очень благодарна вам за помощь!) - person Theo Deep; 13.05.2021
comment
Ну, я могу только предложить добавить еще один принтер, на этот раз специально для типа соотношения. Пост обновлен. - person ivg; 13.05.2021
comment
отвечая на edit2 : вам нужно сделать #require "num";; прежде всего - person ivg; 13.05.2021
comment
Хорошо, итак. 1) В Ocaml работает (поставил реквест), ставлю в новый EDIT 3, чтобы было видно (и после этого сделаю вопрос более читабельным) 2) Второй способ (новый принтер) , вы можете увидеть это в РЕДАКТИРОВАТЬ 4. Это работает, но печатает 2 вместо 2/1. И последнее, но не менее важное, еще раз спасибо. Я хотел бы оценить всю эту помощь, но я не вижу возможности оплатить кофе в вашем профиле :) - person Theo Deep; 13.05.2021
comment
С новой печатью все в порядке, просто новая функция не только печатает, но и упрощает выражение, попробуйте например `div_num (Int 3) (Int 5)` и div_num (Int 10) (Int 5), они будут напечатаны как 3/5 и 2 соответственно. - person ivg; 13.05.2021
comment
и не за что) Сказать спасибо более чем достаточно) - person ivg; 13.05.2021