how to print in ML - sml

I've searched and found several people asking this question, but I can't find an explicit answer.
How can I print a non-string in sml?
For example if I have an instance of an ADT, i.e., of a type declared by datatype, and I would like to print the value for debugging. Am I responsible for writing a function which converts such an object to a string, and then print the string? Or is there some printer library I should use? Or is there some sort of printObject or toString function?
Also how can I print other non-string objects such as true and false?
It would appear that sml knows how to print such objects, because when I compile a file using C-l in emacs, I see output such as the following, showing that sml does know how to print the values.
[opening /Users/jimka/Repos/mciml/ex1.1.sml]
type key = string
datatype tree = LEAF | TREE of tree * string * tree
val empty = LEAF : tree
val insert = fn : key * tree -> tree
val member = fn : key * tree -> bool
val t1 = TREE (LEAF,"a",LEAF) : tree
val t2 = TREE (LEAF,"a",TREE (LEAF,"c",LEAF)) : tree
val t3 = TREE (LEAF,"a",TREE (TREE (LEAF,"b",LEAF),"c",LEAF)) : tree
val it = true : bool
val it = () : unit

How can I print a non-string in sml?
As I understand it, this is not possible (in a portable way). Depending on the implementation you're using it may expose a function that does this.
Also how can I print other non-string objects such as true and false?
Many types with corresponding basis library structures (e.g., int and Int) have a toString function, so you could print a bool b via print (Bool.toString b) and similarity with Int.toString for an int.
Some implementation specific thoughts:
For PolyML, you can use the function PolyML.print to print values of arbitrary types (though you may need to explicitly type annotate; the type of the argument should not have any type variables).
For SML/NJ, you might try taking a look at the approach discussed here https://sourceforge.net/p/smlnj/mailman/message/21897190/, though this seems like more trouble than it's worth.
For MLton, I'm not aware of anything like a polymorphic function, but they have a couple guides on implementing printf or similar.
It looks like Moscow ML supports a function Meta.printVal, but only in an interactive session. I'm not sure what support SML# has for this sort of thing.
Am I responsible for writing a function which converts such an object to a string, and then print the string?
Generally speaking, yes.
It would appear that sml knows how to print such objects
Depending on your SML implementation this is enabled because the REPL has access to more information than a program normally might. For instance, SML/NJ is able to do this because the REPL has access to type information not available elsewhere (for a source, see John Reppy's statements in the linked mailman thread).
You might also find MLton's TypeIndexedValues example page helpful for this sort of thing, though I haven't closely examined it for quality myself.

Related

Printing constructor name in SML

I would like to know whether there would be a way to print the name of the constructor of a datatype from a function in SML. I could find ways to do this in Haskell by deriving the datatype from libraries like show but not in SML.
I need this because I have a very large datatype with lots of constructors which needs to pretty print the data from a function.
Hence the below code wouldn't work for me.
fun print (Cons of var) = "cons"

Is there a function that can make a string representation of any type?

I was desperately looking for the last hour for a method in the OCaml Library which converts an 'a to a string:
'a -> string
Is there something in the library which I just haven't found? Or do I have to do it different (writing everything by my own)?
It is not possible to write a printing function show of type 'a -> string in OCaml.
Indeed, types are erased after compilation in OCaml. (They are in fact erased after the typechecking which is one of the early phase of the compilation pipeline).
Consequently, a function of type 'a -> _ can either:
ignore its argument:
let f _ = "<something>"
peek at the memory representation of a value
let f x = if Obj.is_block x then "<block>" else "<immediate>"
Even peeking at the memory representation of a value has limited utility since many different types will share the same memory representation.
If you want to print a type, you need to create a printer for this type. You can either do this by hand using the Fmt library (or the Format module in the standard library)
type tree = Leaf of int | Node of { left:tree; right: tree }
let pp ppf tree = match tree with
| Leaf d -> Fmt.fp ppf "Leaf %d" d
| Node n -> Fmt.fp ppf "Node { left:%a; right:%a}" pp n.left pp n.right
or by using a ppx (a small preprocessing extension for OCaml) like https://github.com/ocaml-ppx/ppx_deriving.
type tree = Leaf of int | Node of { left:tree; right: tree } [##deriving show]
If you just want a quick hacky solution, you can use dump from theBatteries library. It doesn't work for all cases, but it does work for primitives, lists, etc. It accesses the underlying raw memory representation, hence is able to overcome (to some extent) the difficulties mentioned in the other answers.
You can use it like this (after installing it via opam install batteries):
# #require "batteries";;
# Batteries.dump 1;;
- : string = "1"
# Batteries.dump 1.2;;
- : string = "1.2"
# Batteries.dump [1;2;3];;
- : string = "[1; 2; 3]"
If you want a more "proper" solution, use ppx_deriving as recommended by #octachron. It is much more reliable/maintainable/customizable.
What you are looking for is a meaningful function of type 'a. 'a -> string, with parametric polymorphism (i.e. a single function that can operate the same for all possible types 'a, even those that didn’t exist when the function was created). This is not possible in OCaml. Here are explications depending on your programming background.
Coming from Haskell
If you were expecting such a function because you are familiar with the Haskell function show, then notice that its type is actually show :: Show a => a -> String. It uses an instance of the typeclass Show a, which is implicitly inserted by the compiler at call sites. This is not parametric polymorphism, this is ad-hoc polymorphism (show is overloaded, if you want). There is no such feature in OCaml (yet? there are projects for the future of the language, look for “modular implicits” or “modular explicits”).
Coming from OOP
If you were expecting such a function because you are familiar with OO languages in which every value is an object with a method toString, then this is not the case of OCaml. OCaml does not use the object model pervasively, and run-time representation of OCaml values retains no (or very few) notion of type. I refer you to #octachron’s answer.
Again, toString in OOP is not parametric polymorphism but overloading: there is not a single method toString which is defined for all possible types. Instead there are multiple — possibly very different — implementations of a method of the same name. In some OO languages, programmers try to follow the discipline of implementing a method by that name for every class they define, but it is only a coding practice. One could very well create objects that do not have such a method.
[ Actually, the notions involved in both worlds are pretty similar: Haskell requires an instance of a typeclass Show a providing a function show; OOP requires an object of a class Stringifiable (for instance) providing a method toString. Or, of course, an instance/object of a descendent typeclass/class. ]
Another possibility is to use https://github.com/ocaml-ppx/ppx_deriving with will create the function of Path.To.My.Super.Type.t -> string you can then use with your value. However you still need to track the path of the type by hand but it is better than nothing.
Another project provide feature similar to Batterie https://github.com/reasonml/reason-native/blob/master/src/console/README.md (I haven't tested Batterie so can't give opinion) They have the same limitation: they introspect the runtime encoding so can't get something really useable. I think it was done with windows/browser in mind so if cross plat is required I will test this one before (unless batterie is already pulled). and even if the code source is in reason you can use with same API in OCaml.

Appending to list based on condition in OCaml

I'm trying to create a list of unique by appending to a list, but I'm getting this error.
Error: This expression has type 'a list
but an expression was expected of type unit
in_list is a boolean function that checks whether the value is in the list.
if(in_list x seen_list) then print_string("Already found") else seen_list#x in
List.iter uniq check_list;;
It seems like there must be some small syntactic error I need to fix for the append function. Suggestions?
TL;DR: Lists are immutable in OCaml
According to your code, you seem to believe that lists are mutable in OCaml, and they are not. Hence seen_list#x compute a new list but does not change seen_list.
You could change your code to
let uniq seen_list x =
if in_list x seen_list then
(Printf.printf: "uniq: %d: Already seen.\n" x; seen_list)
else x :: seen_list
in
List.fold_left uniq [] check_list
The uniq function maps a list of integers to a list of integers without repetitions, logging the entries it skips.
This code is obviously intended to be learning material, I guess, nevertheless you should be aware that it most likely implements a Shlemiel the painter's algorithm.
This is a type error, not a syntactic error.
An OCaml function must always return a result of the same type. Right now, when the item is in the list your function tries to return a different type than if the item is not in the list.
Specifically, when the item is already there your function calls print_string, which returns (). This is called unit, and is a placeholder representing no interesting value. When the item isn't already there, your function returns a value of type 'a list. Almost certainly what you need to do is to return a list in all cases.
It's hard to say more without seeing more of your code, but the most usual way to handle this situation is to return the old list when the item is already there and a new, longer list when the item isn't already there.
Update
There are many things to fix in this code, but that's the point of the exercise I assume.
Your next problem seems to be that List.iter is an imperative function, i.e., it wants to do something rather than produce a result. Hence the function that it iterates over the list should return unit (described above). You're using the function uniq instead, which returns a list.
If you want to use a higher-order function like List.iter, which is excellent OCaml style, you will need to use a fold (List.fold_left or List.fold_right), whose purpose is to accumulate a result.

Having an issue with records and tuples in SML

I am trying to solve an exercise in SML like ;
Write an ML program to be used for a multiple choice exam containing 10 questions. Your program should include the following:
o The answer key of the exam
e.g.
val key= “adabcbaadb”;
o Type definition for a record (info) which contains name and answers of a student.
e.g. {name=”Ali”,ans=”abadccdadb”}
o Type definition for a tuple (result) which contains name and score of a student.
e.g. ("Ali",60)
o Write as many functions as needed to take a list of records of type info containing the information of 3 students, calculate their scores, and convert them into a list of tuples of type result. You can write other supporting functions as well
e.g.
- val stuInfo:info list=[{name=”Ali”,ans=”abadccdadb”},
{name=”Ege”,ans=”cbbdacabda”},
{name=”Can”,ans=”adabcbaadb”}];
- val results = calculate(stuInfo);
val results = [("Ali",60),("Ege",20),("Can",100)] : result list
o Write as many functions as needed to calculate the average score, and return the students who received a score above the average.
e.g.
-val aboveList=aboveAvg(results);
val aboveList = [("Ali",60),("Can",100)] : result list
Notes:
 Make sure you give the types of your parameters and return value in all your functions.
 Paranthesize your expressions.
 Use explode function which converts a string to a character array
e.g.
- explode "abc";
val it = [#"a",#"b",#"c"] : char list
My written code for this exercise is below ; but my code is not working :/ Where is my mistake ?
val answer_key="ddacbadbca";
type student_information={s_name:string,s_choice:string};
type student_result=string*int;
val student:info list=[{s_name="David",s_choice="adcbbaccad"},{s_name="John",s_choice="ccdabdbbcc"},{s_name="Alice",s_choice="abdaccacdb"}];
val 3studentsResult:student_result=average(student_information);
fun average ((h::t):student_information list):student_result list=student_score(explode"#ans h",explode"key")::average(t);
val sum=0;
fun student_score(((a::b,c::d):'a list):'a list) = (if(a=c) then sum=sum+10 else sum=sum+0 )::student_score(b,d);
Thanks
There are multiple issues about this code. Before starting, I should recommend you to work on your styling, you can use some spaces and extra lines between functions to see what you are doing easily, like this:
val answer_key = "ddacbadbca";
type student_information = {s_name:string, s_choice:string};
type student_result = string * int;
val student : student_information list =
[{s_name="David", s_choice="adcbbaccad"},
{s_name="John", s_choice="ccdabdbbcc"},
{s_name="Alice", s_choice="abdaccacdb"}];
You might also want to keep your variable and type names consistent. I think the convention is to use snake case (like snake_case) for type names and camel case (like camelCase) for variable and function names.
Here are some of your actual mistakes:
For your student variable, you give the type info list, which doesn't exist in your program. I assume your student_information variable used to be named info, so you should change one of those to the other.
You have a variable named 3studentsResult. Variables cannot start with numbers, they have to start with letters. You have to rename that variable, to something like threeStudentsResult.
In your 3studentsResult variable, you are using the average function that you define later. That doesn't work in Standard ML. You should define a function before using it. (Unless you need mutual recursion, you can use the and keyword then, but it's irrelevant to your problem.) Therefore, define average before 3studentsResult, and define student_score before average.
Even after fixing these, your student_score function is incorrect. I assume sum=sum+10 means that you are trying to change sum's value, like you would do in an imperative programming language. However, Standard ML is a functional language and changing values of variables is something you should avoid in functional programming. In fact, when I talk about "variables" in SML, I mean value declarations that cannot be changed. I recommend you to think about your problem a little bit more and maybe you can divide your problem into sub-problems. Good luck.

Building lists of data types in Haskell

I'm really confused about how your supposed to get data out of typeclasses in haskell. I'm coming for a C background so finding it really difficult that you can't just access the data. What I have is something like this:
data MyType = MyType String deriving (Show)
display :: [MyType] -> IO ()
display ((MyType name):xs) = do
display xs
putStr name
Basically here I want to access 'name' however it just doesn't seem to work. Can I access the data within an instance of a typeclass by just having a reference to the object in my code or do I have to map its contents to variables? and if so how?
Links to good tutorials on this would be appreciated, I've read 'Learn you a Haskell for great good' but when I try to deviate from the examples given there always seems to be to much I need to know to get it done.
-A
I think you might just be missing some little pieces that tie it all together.
Firstly, you have a perfectly fine data type, MyType, that holds strings:
data MyType = MyType String deriving (Show)
Now, you want to write a function that walks a list of such type, printing each element as it goes. We do this via recursion over the list data type.
Since lists have two cases, the empty list, [], and the cons case, (:), we have two branches:
display :: [MyType] -> IO ()
display [] = return ()
display ((MyType name):xs) = do
putStrLn name
display xs
Now, where I think you might have go stuck was building some data of this type. You already know how to take it apart with pattern matching, and you build the data using almost the same syntax. Here's a list of MyType:
table =
[ MyType "john"
, MyType "don"
, MyType "eric"
, MyType "trevor"
]
Finally, you can run your program from main
main = display table
Note, there's no typeclasses here, just algebraic data types (introduced with data).
First of all, I am a bit confused about the words you use. A typeclass is a way to overload functions. What you have is an algebraic data type. The problem you have (if I understood it correctly) is well known. For the purpose of accessing data easier, you could use record syntax:
data Foo = Foo {
bar :: Int
, baz :: String
}
Do you see the similarity to a struct in C? Using record syntax, some interesting things are possible:
bar y -- access member bar of y
y { bar = z } -- Make a new record but with field bar changed to the value of z
and some other thing too.