Having an issue with records and tuples in SML - tuples

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.

Related

how to print in ML

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.

Function definition syntax

I'm trying to implement a particular algorithm. The algorithm isn't very well described but I do have an OCaml implementation. Problem is I don't know OCaml and I'm finding the syntax strange. So here's the first of what might be many questions. Apologies for any mistakes in terminolgy.
One part of the code I have looks like this
type alternative_text = string
type indent = int
module Line =
struct
type t = {s:alternative_text; i:indent}
let make s i = {s;i}
let text (l:t): alternative_text = l.s
let length l = String.length l.s
let indent l = l.i
end
My question concerns the line let text (l:t): alternative_text = l.s. I think I know what this is, a function Line.text which takes a Line.t object and returns the s field, which is a string.
My question concerns the (l:t): alternative_text syntax. This looks like it's specifying the type of the parameter and function result, but why is it necessary? As far as I know let text l = l.s would do exactly the same thing and the other functions are defined without using this extra syntax. So why is it being used here?
Thanks in advance.
The problem with records is that their field names have a scope that's outside the record. So if you have two records with the same field name a, they will clash. I.e., it won't be possible in general to tell whether x.a refers to a field in one record type or the other record type. Depending on the type of x, it could be either.
OCaml tries to give a lot of flexibility in this area by inferring the record type (of x in this example). But if it can't be inferred you need to specify which type you're talking about.
As a side note #glennsl is correct. If you have a non-trivial amount of OCaml to figure out, and you're learning OCaml from scratch, it will be faster to learn OCaml from a book or an online tutorial than to ask individual questions here on StackOverflow.

Erlang: Printing a List with a name always in front of it

I just started learning Erlang so please bear with me if this question seems a little simple.
Hi guys. I've been thinking about it for a while but nothing I come up with seems to be working.
I am writing an Erlang function that is supposed to take a list as an argument then print the list with my name in front of it. For the purposes of this question, let's say my name is "James".
If I type in testmodule:NameInFront("Legible", "Hey", "Think").
Erlang should return ["James", "Legible", "Hey", "Think"]
This is the code I have so far:
-module(testmodule).
-export([NameInFront/1]).
NameInFront(List)-> ["James"]++[List].
It works just fine when I type in just one word, which I guess it the fault of the NameInFront/1 part but I want it to be able to handle any amount of words I type in. Anyone know how I can get my function to handle multiple inputs? Thank you very much.
I'm not quite sure what you mean: whether you want your function to be variadic (take a flexible number of arguments), or you are having trouble getting your lists to join together properly.
Variadic functions are not the way Erlang works. FunctionName/Arity defines the concrete identity of a function in Erlang (discussed here). So our way of having a function take multiple arguments is to make one (or more) of the arguments a list:
print_terms(Terms) -> io:format("~tp~n", [Terms]).
The io:format/2 function itself actually takes a list as its second function, which is how it deals with a variable number of arguments:
print_two_things(ThingOne, ThingTwo) ->
io:format("~tp~n~tp~n", [ThingOne, ThingTwo]).
In your case you want to accept a list of things, add your name to it, and print it out. This is one way to do it.
name_in_front(ListOfStrings) ->
NewList = ["James" | ListOfStrings],
io:format("~p~n", [NewList]).
Using the ++ operator is another (which is actually a different syntax for a recursive operation which expands to the exact same thing, ):
name_in_front(ListOfStrings) ->
NewList = ["James"] ++ ListOfStrings,
io:format("~tp~n", [NewList]).
But that's a little silly, because it is intended to join two strings together in a simple way, and in this case it makes the syntax look weird.
Yet another way would be to more simply write a function that take two arguments and accomplishes the same thing:
any_name_in_front(Name, ListOfThings) ->
io:format("~tp~n", [[Name | ListOfThings]]).
The double [[]] is because io:format/2 takes a list as its second argument, and you want to pass a list of one thing (itself a list) into a single format substitution slot (the "~tp" part).
One thing to note is that capitalization matters in Erlang. It has a meaning. Module and function names are atoms, which are not the same thing as variables. For this reason they must be lowercase, and because they must be lowercase to start with the convention is to use underscores between words instead of usingCamelCase. Because, well, erlangIsNotCpp.
Play around in the shell a bit with the simple elements of the function you want, and once you have them ironed out write it into a source file and give it a try.

What's the OCaml naming convention for "constructors"?

An OCaml module usually contains at least one abstract type whose idiomatic name is t. Also, there's usually a function that constructs a value of that type.
What is the usual / idiomatic name for this?
The StdLib is not consistent here. For example:
There's Array.make and a deprecated function Array.create. So that function should be named make?
On the other hand, there's Buffer.create but not Buffer.make. So that function should be named create?
Some people find this way of module design makes OCaml programming easier, but this is not a mandatory OCaml programming style, and I do not think there is no official name for it. I personally call it "1-data-type-per-1-module" style. (I wrote a blog post about this but it is in Japanese. I hope some autotranslator gives some useful information to you ...)
Defining a module dedicated to one data type and fix the name of the type t has some values:
Nice namespacing
Module names explain about what its type and values are, therefore you do not need to repeat type names inside: Buffer.add_string instead of add_string_to_buffer, and Buffer.create instead of create_buffer. You can also avoid typing the same module names with local module open:
let f () =
let open Buffer in
let b = create 10 in (* instead of Buffer.create *)
add_string b "hello"; (* instead of Buffer.add_string *)
contents b (* instead of Buffer.contents *)
Easy ML functor application
If an ML functor takes an argument module with a data type, we have a convention that the type should be called t. Modules with data type t are easily applied to these functors without renaming of the type.
For Array.create and Array.make, I think this is to follow the distinction of String.create and String.make.
String.create is to create a string with uninitialized contents. The created string contains random bytes.
String.make is to create a string filled with the given char.
We had Array.create for long, to create an array whose contents are filled with the given value. This behavior corresponds with String.make rather than String.create. That's why it is now renamed to Array.make, and Array.create is obsolete.
We cannot have Array.create in OCaml with the same behaviour of String.create. Unlike strings, arrays cannot be created without initialization, since random bytes may not represent a valid OCaml value for the content in general, which leads to a program crash.
Following this, personally I use X.create for a function to create an X.t which does not require an initial value to fill it. I use X.make if it needs something to fill.
I had the same question when I picked up the language a long time ago. I never use make and I think few people do.
Nowadays I use create for heavy, often imperative or stateful values, e.g. a Unicode text segmenter. And I use v for, functional, lighter values in DSL/combinator based settings, e.g. the various constructors in Gg, for example for 2D vectors, or colors.
As camlspotter mentions in his answer the standard library distinguishes make and create for values that need an initial value to fill in. I think it's better to be regular here and always use create regardless. If your values support an optional initial fill value, add an optional argument to create rather than multiply the API entry points.

user defined type for strings which starts with Letter

I want to have user-defined type in Ocaml which represents strings which starts with English letter and afterwards can have letters or digits. Is it possible to define such custom type?
Jeffrey Scofield is right: there is no way in OCaml to define a type that would be the subset of strings verifying a given condition. You might however simulate that to some extent with a module and abstract or private data type, as in:
module Ident : sig
type t = private string
val create: string -> t
val (^): t -> t -> t
(* declare, and define below other functions as needed *)
end = struct
type t = string
let create s = (* do some check *) s
let (^) s1 s2 = create (s1 ^ s2)
end;;
Of course, the create function should check that the first char of s is a letter and the other ones letters or digits and raise an exception if this is not the case, but this is left a an exercise. This way, you know that any s of type Ident.t respects the conditions checked in create: by making the type synonym private in the signature, you ensure that you must go through one of the functions of Ident to create such value. Conversely (s:>string) is recognized as a string, hence you can still use all built-in functions over it (but you'll get back string, not Ident.t).
Note however that there is particular issue with string: they are mutable (although that is bound to change in the upcoming 4.02 version), so that you can alter an element of Ident.t afterwards:
let foo = "x0";;
let bar = Ident.create foo;;
foo.[0] <- '5';;
bar;;
will produce
- : Ident.t = "50"
If you restrict yourself to never modify a string in place (again this will be the default in the next OCaml's version), this cannot happen.
It's a little hard to answer, but I think the most straightforward answer is no. You want the type to be constrained by values, and this isn't something that's possible in OCaml. You need a language with dependent types for that.
You can define an OCaml type that represents such strings, but its values wouldn't also be strings. You couldn't use strings like "a15" as values of the type, or use the built-in ^ operator on them, etc. A value might look like S(Aa, [B1; B5]) (say). This is far too cumbersome to be useful.