how to invoke SML/NJ's built-in pretty printer from a program?

View: New views
6 Messages — Rating Filter:   Alert me  

how to invoke SML/NJ's built-in pretty printer from a program?

by Joe Wells :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

SML/NJ has a built-in pretty printer for printing values of various
types used by the top-level REPL.

How do I invoke it from a program?

There is a function PrettyPrint.pp_to_string of type int -> (stream ->
'a -> unit) -> 'a -> string, but to use it I would have to give it a
value of type (stream -> 'a -> unit).  How do I construct this
argument?

To make my question concrete, in the following SML program, by what do
I replace “magic_pretty_printer” to make the program print “Happy,
happy, joy, joy!”?

  datatype Xyzzy = C of Xyzzy * Xyzzy | D of string

  val plugh = C (D "hello",D "sailor")
  val plugh_string = "C (D \"hello\",D \"sailor\")"

  if ((magic_pretty_printer plugh) = plugh_string)
     then (print "Happy, happy, joy, joy!\n")
     else (raise (Fail "magic pretty printer gave wrong result"))

I've browsed around the source for a while and failed to find what I
need.  Any hints would be helpful.

I'd rather not use Backend.Interact.evalStream and capture the output
somehow, but if that is my only option I would be grateful for an
example of how to do it.

Thanks for your time in considering this question.

--
Joe


--
Heriot-Watt University is a Scottish charity
registered under charity number SC000278.


------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
_______________________________________________
Smlnj-list mailing list
Smlnj-list@...
https://lists.sourceforge.net/lists/listinfo/smlnj-list

Re: how to invoke SML/NJ's built-in pretty printer from a program?

by John Reppy :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I don't think that what you want is possible in SML/NJ, since it  
requires
runtime type information.  In the REPL, we are able to pretty-print  
results
because we know their type, but that is not true in general.  Sorry.

        - John

On Feb 26, 2009, at 7:10 AM, Joe Wells wrote:

> SML/NJ has a built-in pretty printer for printing values of various
> types used by the top-level REPL.
>
> How do I invoke it from a program?
>
> There is a function PrettyPrint.pp_to_string of type int -> (stream ->
> 'a -> unit) -> 'a -> string, but to use it I would have to give it a
> value of type (stream -> 'a -> unit).  How do I construct this
> argument?
>
> To make my question concrete, in the following SML program, by what do
> I replace “magic_pretty_printer” to make the program print “Happy,
> happy, joy, joy!”?
>
>  datatype Xyzzy = C of Xyzzy * Xyzzy | D of string
>
>  val plugh = C (D "hello",D "sailor")
>  val plugh_string = "C (D \"hello\",D \"sailor\")"
>
>  if ((magic_pretty_printer plugh) = plugh_string)
>     then (print "Happy, happy, joy, joy!\n")
>     else (raise (Fail "magic pretty printer gave wrong result"))
>
> I've browsed around the source for a while and failed to find what I
> need.  Any hints would be helpful.
>
> I'd rather not use Backend.Interact.evalStream and capture the output
> somehow, but if that is my only option I would be grateful for an
> example of how to do it.
>
> Thanks for your time in considering this question.
>
> --
> Joe
>
>
> --
> Heriot-Watt University is a Scottish charity
> registered under charity number SC000278.
>
>
> ------------------------------------------------------------------------------
> Open Source Business Conference (OSBC), March 24-25, 2009, San  
> Francisco, CA
> -OSBC tackles the biggest issue in open source: Open Sourcing the  
> Enterprise
> -Strategies to boost innovation and cut costs with open source  
> participation
> -Receive a $600 discount off the registration fee with the source  
> code: SFAD
> http://p.sf.net/sfu/XcvMzF8H
> _______________________________________________
> Smlnj-list mailing list
> Smlnj-list@...
> https://lists.sourceforge.net/lists/listinfo/smlnj-list


------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
_______________________________________________
Smlnj-list mailing list
Smlnj-list@...
https://lists.sourceforge.net/lists/listinfo/smlnj-list

Re: how to invoke SML/NJ's built-in pretty printer from a program?

by Joe Wells :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

John Reppy <jhr@...> writes:

> I don't think that what you want is possible in SML/NJ, since it
> requires
> runtime type information.  In the REPL, we are able to pretty-print
> results
> because we know their type, but that is not true in general.  Sorry.

Thanks very much for the answer.

Let me ask a followup question.  Is there a way to add type
information to the global environment (what is in EnvRef.state) from a
program?  Here is a concrete example of what I have in mind:

  let
    val x = "world!”;
  in
    do_magic ();
    Backend.Interact.useStream (TextIO.openString "print (\"Hello, \"^x);")
  end

Is there anything I can replace do_magic by in the above example to
make it work?

--
Thanks,

Joe

> - John
>
> On Feb 26, 2009, at 7:10 AM, Joe Wells wrote:
>
>> SML/NJ has a built-in pretty printer for printing values of various
>> types used by the top-level REPL.
>>
>> How do I invoke it from a program?
>>
>> There is a function PrettyPrint.pp_to_string of type int -> (stream ->
>> 'a -> unit) -> 'a -> string, but to use it I would have to give it a
>> value of type (stream -> 'a -> unit).  How do I construct this
>> argument?
>>
>> To make my question concrete, in the following SML program, by what do
>> I replace “magic_pretty_printer” to make the program print “Happy,
>> happy, joy, joy!”?
>>
>>  datatype Xyzzy = C of Xyzzy * Xyzzy | D of string
>>
>>  val plugh = C (D "hello",D "sailor")
>>  val plugh_string = "C (D \"hello\",D \"sailor\")"
>>
>>  if ((magic_pretty_printer plugh) = plugh_string)
>>     then (print "Happy, happy, joy, joy!\n")
>>     else (raise (Fail "magic pretty printer gave wrong result"))
>>
>> I've browsed around the source for a while and failed to find what I
>> need.  Any hints would be helpful.
>>
>> I'd rather not use Backend.Interact.evalStream and capture the output
>> somehow, but if that is my only option I would be grateful for an
>> example of how to do it.
>>
>> Thanks for your time in considering this question.
>>
>> --
>> Joe


--
Heriot-Watt University is a Scottish charity
registered under charity number SC000278.


------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
_______________________________________________
Smlnj-list mailing list
Smlnj-list@...
https://lists.sourceforge.net/lists/listinfo/smlnj-list

Re: how to invoke SML/NJ's built-in pretty printer from a program?

by Joe Wells :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Joe Wells <jbw@...> writes:

> John Reppy <jhr@...> writes:
>
>> I don't think that what you want is possible in SML/NJ, since it
>> requires runtime type information.  In the REPL, we are able to
>> pretty-print results because we know their type, but that is not
>> true in general.  Sorry.
>
> Thanks very much for the answer.
>
> Let me ask a followup question.  Is there a way to add type
> information to the global environment (what is in EnvRef.state) from
> a program?  Here is a concrete example of what I have in mind:
>
>   let
>     val x = "world!”;
>   in
>     do_magic ();
>     Backend.Interact.useStream (TextIO.openString "print (\"Hello, \"^x);")
>   end

Here is maybe a better version of what I have in mind:

  let
    val x = "world!”;
  in
    put_binding_of_type_string_for_identifier_y_in_global_environment x;
    Backend.Interact.useStream (TextIO.openString "print (\"Hello, \"^y);")
  end

That's less confusing than what I wrote in the previous message.  Is
there any way to implement
put_binding_of_type_string_for_identifier_y_in_global_environment so
that it will work when called from inside a program like this?

--
Joe

> Is there anything I can replace do_magic by in the above example to
> make it work?
>
> --
> Thanks,
>
> Joe
>
>> - John
>>
>> On Feb 26, 2009, at 7:10 AM, Joe Wells wrote:
>>
>>> SML/NJ has a built-in pretty printer for printing values of various
>>> types used by the top-level REPL.
>>>
>>> How do I invoke it from a program?
>>>
>>> There is a function PrettyPrint.pp_to_string of type int -> (stream ->
>>> 'a -> unit) -> 'a -> string, but to use it I would have to give it a
>>> value of type (stream -> 'a -> unit).  How do I construct this
>>> argument?
>>>
>>> To make my question concrete, in the following SML program, by what do
>>> I replace “magic_pretty_printer” to make the program print “Happy,
>>> happy, joy, joy!”?
>>>
>>>  datatype Xyzzy = C of Xyzzy * Xyzzy | D of string
>>>
>>>  val plugh = C (D "hello",D "sailor")
>>>  val plugh_string = "C (D \"hello\",D \"sailor\")"
>>>
>>>  if ((magic_pretty_printer plugh) = plugh_string)
>>>     then (print "Happy, happy, joy, joy!\n")
>>>     else (raise (Fail "magic pretty printer gave wrong result"))
>>>
>>> I've browsed around the source for a while and failed to find what I
>>> need.  Any hints would be helpful.
>>>
>>> I'd rather not use Backend.Interact.evalStream and capture the output
>>> somehow, but if that is my only option I would be grateful for an
>>> example of how to do it.
>>>
>>> Thanks for your time in considering this question.
>>>
>>> --
>>> Joe


--
Heriot-Watt University is a Scottish charity
registered under charity number SC000278.


------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
_______________________________________________
Smlnj-list mailing list
Smlnj-list@...
https://lists.sourceforge.net/lists/listinfo/smlnj-list

Re: how to invoke SML/NJ's built-in pretty printer from a program?

by Joe Wells-6 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

John Reppy <jhr@...> writes:

> I don't think that what you want is possible in SML/NJ, since it
> requires runtime type information.  In the REPL, we are able to
> pretty-print results because we know their type, but that is not
> true in general.  Sorry.

Hi, John,

Appended below is one way to do it.  Sadly, it's not elegant.

Here are some thoughts that occur to me based on what I needed to do.

1. It would be helpful if there was some easy way to force the
   declarations already processed in a file to be contributed to the
   global environment so that “use” can use them.  Right now I have to
   split my SML into two files both processed with useFile (by the
   command-line processing).  Not only is this awkward, but it
   interferes with modularity because any portion of a large program
   that wants to use pretty printing will have to contribute something
   to the first file that gets loaded.

2. It is awkward to have to depend on the side effect of declarations
   being printed by useFile.  Among other problems with this, I have
   to strip off the “val x =” prefix and the type suffix to get the
   desired pretty-printed result.  It would be really nice if the
   pretty printer were exported.  At the very least, it seems like it
   should not be to hard to allow directly requesting the pretty
   printing of the value bound to an identifier in the global
   environment (whose type will therefore already be known).

3. It would be nice if there was some way to tell the pretty printer
   to place no limits on nesting.  Right now, one must specify large
   positive limits and hope they are big enough.  (I suppose one could
   avoid using a bad result by testing to see if the pretty printed
   result gets parsed as the same value, but one should not need to do
   that.)

I hope this message is somehow interesting and useful.

--
Joe

> - John
>
> On Feb 26, 2009, at 7:10 AM, Joe Wells wrote:
>
>> SML/NJ has a built-in pretty printer for printing values of various
>> types used by the top-level REPL.
>>
>> How do I invoke it from a program?
>>
>> There is a function PrettyPrint.pp_to_string of type int -> (stream ->
>> 'a -> unit) -> 'a -> string, but to use it I would have to give it a
>> value of type (stream -> 'a -> unit).  How do I construct this
>> argument?
>>
>> To make my question concrete, in the following SML program, by what do
>> I replace “magic_pretty_printer” to make the program print “Happy,
>> happy, joy, joy!”?
>>
>>  datatype Xyzzy = C of Xyzzy * Xyzzy | D of string
>>
>>  val plugh = C (D "hello",D "sailor")
>>  val plugh_string = "C (D \"hello\",D \"sailor\")"
>>
>>  if ((magic_pretty_printer plugh) = plugh_string)
>>     then (print "Happy, happy, joy, joy!\n")
>>     else (raise (Fail "magic pretty printer gave wrong result"))
>>
>> I've browsed around the source for a while and failed to find what I
>> need.  Any hints would be helpful.
>>
>> I'd rather not use Backend.Interact.evalStream and capture the output
>> somehow, but if that is my only option I would be grateful for an
>> example of how to do it.

======================================================================
#!/bin/bash
# -*-SML-*-
#(*
TmpDir="`mktemp -d -t smlnj-script.XXXXXX`"
CleanUp () { rm -r "$TmpDir"; }
trap 'CleanUp; exit 1' INT TERM HUP
trap CleanUp EXIT
ln -s /dev/fd/4 "$TmpDir/a.sml"
ln -s /dev/fd/5 "$TmpDir/b.sml"
#*)
sml -Ccm.verbose=false "$TmpDir/a.sml" "$TmpDir/b.sml" XyzzyPlugh "$0" "$@" 3<&0 <<'AAAA' 4<&0- <<'BBBB' 5<&0- 0<&3-

(* Control.Print.out := { flush = fn () => (), say = fn _ => () }; *)

datatype Xyzzy = C of Xyzzy * Xyzzy | D of string
val xyzzy_tmp : Xyzzy option ref = ref NONE;

AAAA

fun evalString s =
  Backend.Interact.evalStream (TextIO.openString s, EnvRef.combined ());

fun unwind_protect body unwind_fn =
    (  (body ())
     before
       (* EEEK!  If this use of unwind_fn raises an exception, then unwind_fn will be run again from the exception handler. *)
       (unwind_fn ()))
  handle
    e => (unwind_fn (); raise e);

fun capturePrinting f =
  let
    val old_out = ! Control.Print.out
    val data = ref ""
  in
    Control.Print.out :=
      { flush = (fn () => ()),
        say = (fn s => data := !data ^ s) };
    unwind_protect
      (fn () => (f (); !data))
      (fn () => (Control.Print.out := old_out))
  end;

fun format_xyzzy xyz =
  (xyzzy_tmp := SOME xyz;
   (* *** TODO: must ensure printing is not truncated due to depth/length/etc. limits *)
   let val e = "val x = valOf (! xyzzy_tmp);"
       (* val _ = print (e^"\n") *)
       val s = capturePrinting (fn () => evalString e)
   in (* the length of "val x = " is 8, the length of " : Xyzzy\n" is 9 *)
      String.substring (s, 8, (String.size s) - 9 - 8)
   end)

val plugh = C (D "hello",D "sailor")
val plugh_string = "C (D \"hello\",D \"sailor\")"
val z = format_xyzzy plugh;
if (z = plugh_string)
   then (print "Happy, happy, joy, joy!\n")
   else (raise (Fail "magic pretty printer gave wrong result"));

ignore (OS.Process.exit OS.Process.success);

BBBB


--
Heriot-Watt University is a Scottish charity
registered under charity number SC000278.


------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Smlnj-list mailing list
Smlnj-list@...
https://lists.sourceforge.net/lists/listinfo/smlnj-list

Re: how to invoke SML/NJ's built-in pretty printer from a program?

by Joe Wells :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Joe Wells <jbw@...> writes:

> Here are some thoughts that occur to me based on what I needed to
> do.
>
> 1. It would be helpful if there was some easy way to force the
>    declarations already processed in a file to be contributed to the
>    global environment so that “use” can use them.  Right now I have
>    to split my SML into two files both processed with useFile (by
>    the command-line processing).  Not only is this awkward, but it
>    interferes with modularity because any portion of a large program
>    that wants to use pretty printing will have to contribute
>    something to the first file that gets loaded.

Okay, I now have a better understanding of this issue.

What I was doing in my previous message involved this arrangement of
nested function calls:

  procCmdLine (CM's function to handle command-line arguments)
   |
   +-useFile
   |
   +-useFile
      |
      +-evalStream (the one from Interact, not the one from EvalLoop)

Because of some failures I encountered, I had gained the wrong
understanding that declarations processed by an invocation of useFile
would not be available to a nested useFile.  That is, given a stack of
function calls like

  useFile "a.sml"
   |
   +-useFile "b.sml"

I had reached the wrong understanding that the declarations in b.sml
would not be able to use datatypes or value identifiers declared in
a.sml prior to the invocation of useFile.

I know that this problem really does happen when the (useFile "b.sml")
invocation is inside the same top-level form as the declarations that
b.sml wants to use, but I'm pretty sure I was not doing this, so I am
confused as to how I got confused.

So anyway I now understand that this works fine.

The other issues I raised are still a concern.  Is there anything that
can be done about them?

> 2. It is awkward to have to depend on the side effect of
>    declarations being printed by useFile.  Among other problems with
>    this, I have to strip off the “val x =” prefix and the type
>    suffix to get the desired pretty-printed result.  It would be
>    really nice if the pretty printer were exported.  At the very
>    least, it seems like it should not be to hard to allow directly
>    requesting the pretty printing of the value bound to an
>    identifier in the global environment (whose type will therefore
>    already be known).
>
> 3. It would be nice if there was some way to tell the pretty printer
>    to place no limits on nesting.  Right now, one must specify large
>    positive limits and hope they are big enough.  (I suppose one
>    could avoid using a bad result by testing to see if the pretty
>    printed result gets parsed as the same value, but one should not
>    need to do that.)

Thanks for your time in any responses you make to my message.

--
Joe

>> On Feb 26, 2009, at 7:10 AM, Joe Wells wrote:
>>
>>> SML/NJ has a built-in pretty printer for printing values of various
>>> types used by the top-level REPL.
>>>
>>> How do I invoke it from a program?
>>>
>>> There is a function PrettyPrint.pp_to_string of type int -> (stream ->
>>> 'a -> unit) -> 'a -> string, but to use it I would have to give it a
>>> value of type (stream -> 'a -> unit).  How do I construct this
>>> argument?
>>>
>>> To make my question concrete, in the following SML program, by what do
>>> I replace “magic_pretty_printer” to make the program print “Happy,
>>> happy, joy, joy!”?
>>>
>>>  datatype Xyzzy = C of Xyzzy * Xyzzy | D of string
>>>
>>>  val plugh = C (D "hello",D "sailor")
>>>  val plugh_string = "C (D \"hello\",D \"sailor\")"
>>>
>>>  if ((magic_pretty_printer plugh) = plugh_string)
>>>     then (print "Happy, happy, joy, joy!\n")
>>>     else (raise (Fail "magic pretty printer gave wrong result"))
>>>
>>> I've browsed around the source for a while and failed to find what I
>>> need.  Any hints would be helpful.
>>>
>>> I'd rather not use Backend.Interact.evalStream and capture the output
>>> somehow, but if that is my only option I would be grateful for an
>>> example of how to do it.
>
> ======================================================================
> #!/bin/bash
> # -*-SML-*-
> #(*
> TmpDir="`mktemp -d -t smlnj-script.XXXXXX`"
> CleanUp () { rm -r "$TmpDir"; }
> trap 'CleanUp; exit 1' INT TERM HUP
> trap CleanUp EXIT
> ln -s /dev/fd/4 "$TmpDir/a.sml"
> ln -s /dev/fd/5 "$TmpDir/b.sml"
> #*)
> sml -Ccm.verbose=false "$TmpDir/a.sml" "$TmpDir/b.sml" XyzzyPlugh "$0" "$@" 3<&0 <<'AAAA' 4<&0- <<'BBBB' 5<&0- 0<&3-
>
> (* Control.Print.out := { flush = fn () => (), say = fn _ => () }; *)
>
> datatype Xyzzy = C of Xyzzy * Xyzzy | D of string
> val xyzzy_tmp : Xyzzy option ref = ref NONE;
>
> AAAA
>
> fun evalString s =
>   Backend.Interact.evalStream (TextIO.openString s, EnvRef.combined ());
>
> fun unwind_protect body unwind_fn =
>     (  (body ())
>      before
>        (* EEEK!  If this use of unwind_fn raises an exception, then unwind_fn will be run again from the exception handler. *)
>        (unwind_fn ()))
>   handle
>     e => (unwind_fn (); raise e);
>
> fun capturePrinting f =
>   let
>     val old_out = ! Control.Print.out
>     val data = ref ""
>   in
>     Control.Print.out :=
>       { flush = (fn () => ()),
>         say = (fn s => data := !data ^ s) };
>     unwind_protect
>       (fn () => (f (); !data))
>       (fn () => (Control.Print.out := old_out))
>   end;
>
> fun format_xyzzy xyz =
>   (xyzzy_tmp := SOME xyz;
>    (* *** TODO: must ensure printing is not truncated due to depth/length/etc. limits *)
>    let val e = "val x = valOf (! xyzzy_tmp);"
>        (* val _ = print (e^"\n") *)
>        val s = capturePrinting (fn () => evalString e)
>    in (* the length of "val x = " is 8, the length of " : Xyzzy\n" is 9 *)
>       String.substring (s, 8, (String.size s) - 9 - 8)
>    end)
>
> val plugh = C (D "hello",D "sailor")
> val plugh_string = "C (D \"hello\",D \"sailor\")"
> val z = format_xyzzy plugh;
> if (z = plugh_string)
>    then (print "Happy, happy, joy, joy!\n")
>    else (raise (Fail "magic pretty printer gave wrong result"));
>
> ignore (OS.Process.exit OS.Process.success);
>
> BBBB
>
>
> --
> Heriot-Watt University is a Scottish charity
> registered under charity number SC000278.
>
>
> ------------------------------------------------------------------------------
> Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
> powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
> easily build your RIAs with Flex Builder, the Eclipse(TM)based development
> software that enables intelligent coding and step-through debugging.
> Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
> _______________________________________________
> Smlnj-list mailing list
> Smlnj-list@...
> https://lists.sourceforge.net/lists/listinfo/smlnj-list


--
Heriot-Watt University is a Scottish charity
registered under charity number SC000278.


------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Smlnj-list mailing list
Smlnj-list@...
https://lists.sourceforge.net/lists/listinfo/smlnj-list