2

I continue with my exploration on the Num library of Ocaml, with the reason that one whole library about logics was written using it.

Today, I would like to make the negative of a rational number. Obtain -1/2, from 1/2.

To do so, I think that, given an a of type Ratio.ratio, I can compute the negative of it (and return a ratio, not a num) this way:

ratio_of_num (minus_num (num_of_ratio a))

(Functions from: https://ocaml.org/releases/4.05/htmlman/libref/Num.html#TYPEnum)

Now, I would like to check the result, but I always get this solution: Ratio.ratio = <abstr>

The point is that now I realize that I always get this solution when I use ratio_of_num. For instance:

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

I have searched a bit and found this question (OCaml toplevel output formatting) where a different function (ratio_of_int 2) was used, but seems no longer possible. Maybe that ratio is a different library.

Any help?

PS: By the way, in order to replace num in the future, I am trying to install Zarith with opam, but cannot.

My problem is I do opam install zarith and this is displayed:

┌─ 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

So I do opam install gmp and I get:

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

Which offers me no clue on how to continue trying. Any help with this also?

I would appreciate any answer whether for the first question or the second one!!

Here below, I post some editions that have been added to the question, as a result of the conversation below:

EDIT (Solved adding the needed #require)

I have done what @ivg has suggested, but still does not work (I do the initial open Num, because it will ask it otherwise):


─( 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>

EDIT 2 (Also needed a #require)

I have also tried Ocaml instead of utop, but the error is worse:

        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'
# 

EDIT 3 (Works in Ocaml, instead of 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>
# 

EDIT 4 (Works in utop, note that printing simplifies the result when it is an integer)

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 # 

Theo Deep
  • 666
  • 4
  • 15

1 Answers1

4

The reason why you have <abstr> instead of the actual representation is that the top-level (aka interpreter) doesn't know how to print the num object. It is easy to teach the top-level, using the #install_printer directive, e.g.,


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>
# 

So we defined the pretty-printing function,

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

And then used the #install_printer directive to install it in the top-level,

# #install_printer pp_num;;

and now every time we have num it will be printed for us.

You can also use this pp_num function together with other Format module functions (that are used for pretty printing), e.g.,

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

It might be that an older version of OCaml is unable to derive how to print ratio from the nums itself, so we can help it by defining an additional printer,

# 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.

For zarith you need to install system dependencies. You can use opam for that, e.g.,

opam depext --install zarith

it will install the system dependencies (the gmp library) using your operating system package manager and then install the zarith library.

ivg
  • 34,431
  • 2
  • 35
  • 63
  • Hi! It makes sense, so a pretty printer is needed. The point is I have made what you said, and the problem still remains.. I do the same and then (look my EDIT on the initial question). – Theo Deep May 12 '21 at 21:17
  • 1
    that is strange, can you try `ocaml` instead of `utop`? It also could be that your OCaml is very old... what version are you using? – ivg May 12 '21 at 21:21
  • If I do it in Ocaml, you can see the response in the EDIT2 . I also ask ```which ocaml``` and responds ```4.10.2``` so... (I really thank your help, by the way!) – Theo Deep May 12 '21 at 21:23
  • 1
    Well, I can only suggest adding a yet another printer, this time specifically for the ratio type. The post is updated. – ivg May 12 '21 at 21:27
  • 1
    responsing to edit2 : you need to do `#require "num";;` before anything else – ivg May 12 '21 at 21:28
  • Okay so. 1) In Ocaml it works (I have put the require), I put it in a new EDIT 3 so that you can see it (and after that I will make the question more readable) 2) The second way (the new printer), you can see it in EDIT 4. It works, but, prints 2 instead of 2/1. And last but no least, thanks again. I would like to appreciate all this help, but I do not see any way to pay for a coffee on your profile :) – Theo Deep May 12 '21 at 21:32
  • 1
    The new printing is fine, it is just the new function not only prints but simplifies the expression, try for example ` div_num (Int 3) (Int 5)` and `div_num (Int 10) (Int 5)`, they will be printed as `3/5` and `2` correspondingly. – ivg May 12 '21 at 21:39
  • 1
    and you're welcome) Saying thanks is more than enough) – ivg May 12 '21 at 21:39