SML Program for Comparing Time Stamp - sml

I am doing an exercise in which two time stamps are given, and I have to find which is large. This program is written in SML. So I come up with this program...
val record1 = {hour = 11, min = 45, f = "PM"};
val record2 = {hour = 2,min = 13,f = "AM"};
fun timerrecord(record1,record2)=
if (#f record1 = "PM") andalso (#f record2="AM") then "t1 comes First"
else if(#f record1 = "AM") andalso (#f record1="PM") then "t2 comes First"
else if (#hour record1 > #hour record1) then "t1 comes First"
else if (#hour record1 < #hour record1) then "t2 comes First"
else if (#min record1 > #min record1) then "t1 comes First"
else "t2 comes First";
The problem is when I write it without the function, it gives the correct result but when I put code in that function (as given above) it gives an error...UNRESOLVED FLEX RECORD.
t1,t2 and record1,record2 are timestamps.
I am new to SML, so any help would be helpful. Thanks in advance.

As user987339 said, you can put in type annotations to resolve the types. But the common way to do this in ML is not to use record selectors #label in the first place, but to rely on pattern matching, which implies the types:
fun timerRecord({hour = h1, min = m1, f = f1}, {hour = h2, min = m2, f = f2}) =
if f1 = "PM" andalso f2 = "AM" then "t1 comes first"
else if f1 = "AM" andalso f2 = "PM" then "t2 comes first"
else if h1 > h2 then "t2 comes first"
else if h1 < h2 then "t1 comes first"
else if m1 > m2 then "t2 comes first"
else "t1 comes first"
(Fixed a couple of cases.)

You have to define record type in order to compile this function. So add:
type recc = {hour:int, min:int, f:string};
and change your function signature to:
fun timerrecord(record1:recc,record2:recc)=
Or you can do it a bit "dirty", just by changing function signature to:
fun timerrecord(record1:{hour:int, min:int, f:string},record2:{hour:int, min:int, f:string})=
Depends how DRY you are :-)
PS: Find what DRY means.

Related

Simplify a repetitive pattern using monads

I'm actually not sure this is doable with monads or that it should be done with them and I'm looking for a solution rather than solve it with monads if monads are not the solution.
Let's say I have the following code (simplified but the idea is here):
module IM = Map.Make (Int)
let f k v m =
if IM.mem k m then (m, true)
else (IM.add k v m, false)
let a =
let m = IM.empty in
let m, res = f 0 "Zero" m in
if res then
let m, res = f 1 "One" m in
if res then f 2 "Two" m else (m, res)
else (m, res)
I'm repeating multiple times:
let value, boolean = function application to value and other values in
if boolean then another function application to the new value and other values (not the same as the first one)
else the result
This means that these functions don't necessarily have the same type but they all return a a IM.t * bool (a being the same type for every function)
I wondered if it was possible to create an inline operator that would allow me to do it.
I tried something like:
module EqMonad = struct
let ( let* ) (t, res) f2 = if res then f2 t else (t, false)
let return t = t
end
But it'll obviously not work because f2 takes more than one argument but needs to receive t as its last argument.
I guess I could summarize my problem like this:
Is it possible to have monads wrapping variadic functions?
Your solution works (with return corrected to be the monadic return) and is a restricted version of the error monad:
let return x = x, true
let a =
let m = IM.empty in
let* m = f 0 "Zero" m in
let* m = f 1 "One" m in
let* m = f 2 "Two" m in
return m
However, since the control flow never depends on the value of m, this is a sign that it might simpler to use a regular function:
let rec add_first_fresh m l = match l with
| [] -> None
| (k,v):: q ->
if IM.mem k m then add_first_fresh m q
else Some (IM.add k v m)
let a = add_first_fresh IM.empty
[0, "Zero";
1, "One";
2, "Two"
]

Using "let" to assign a tuple to a value in sml

Im trying to write a function that does the following, takes in :
[ #"t" ,#"h" ,#"e" ,#" " ,#"c" ,#"a" ,#"t" ]
The following is the output:
( [#"t" ,#"h" ,#"e" ] , [#" " ,#"c" ,#"a" ,#"t" ] )
so far I have..
fun isLetter c = #"a" <= c andalso c <= #"z";
//(this works fine and is used within the main function wordPop)
fun wordPop [] = ([],[])
| wordPop (hd::tl) = if not (isLetter hd)
then ([], hd::tl)
else (* ...not too sure... (1) *)
I know that I have to do something that looks like this at (1)
let (wordPop tl) in (x,y) end;
and somehow add hd to x. But not 100% sure how to do this.
Sounds like homework, so here is a hint:
In the non-basis case (hd::tl), if isLetter hd is false then you are ready to directly return something (no need for a recursive function call). Think carefully about what you want to return if the input looks like just explode(" cat") (i.e. [#" ", "c", "a", "t"] -- note the space).
As far as the other case (isLetter hd evaluating to true) goes, suppose you are processing the characters in "he cat". Then hd = #"h" and tl = [#"e", #" ", "c", "a", "t"].
If in this context you execute
let val (x,y) = wordPop tl
then x = [#"e"] and y = [#" ", "c", "a", "t"].
Given such x and y -- where do you want to place hd = #"h" before returning?
The final solution I got:
fun isLetter c = #"a" <= c andalso c <= #"z";
fun wordPop [] = ([],[]) |
wordPop (hd::tl) = if(not (isLetter hd))
then ([],(hd::tl))
else let val (x,y) = wordPop tl in (hd::x,y) end;

sml error inserting EQUALOP

I'm writing a function in sml using emacs and when I try to compile this code
fun tryDivide small n =
if n = 1 then true
else if ((small mod n) = 0) then tryDivide small (n-1)
else false
fun lcmHelper small div =
if tryDivide (small div) = false then lcmHelper ((small+div) div)
else small
(*Start by calling this*)
fun lcm d =
val small = d
lcmHelper (small d)
It is supposed to find the lowest value that can be divided by d (fun lcm d)
I am pretty sure that the algorithm works, but there are syntax errors.
At the start of the "fun lcm d =" I get an error that says "Error Inserting EQUALOP"
Any ideas what might be causing this?
Thanks in advance!
fun lcm d =
let
val small = d
in
lcmHelper (small d)
end

SML program and tuple

I am doing an exercise in which two time stamps are given and I have to find which is large. This program is written in SML.So I come up with this program....
type triple = {int,int,string};
val record1 = (11,45,"PM");
val record2 = (2,13,"AM");
fun timerrecord(record1:triple,record2:triple)=
let val (hour1:int,min1:int,f1:string) = record1;
val (hour2:int,min2:int,f2:string) = record2
in
if (f1= "AM") andalso (f2="PM") then "t1 comes First"
else if(f1 = "PM") andalso (f2="AM") then "t2 comes First"
else if (hour1 < hour2) then "t1 comes First"
else if (hour1 > hour2) then "t2 comes First"
else if (min1 < min2) then "t1 comes First"
else "t2 comes First";
above program is not executing as a whole but individual logic is because of tuple.I am not able to get best use of tuple to comparing 2 time stamps.
Also I want to know how to acess tuple as if it is known then we can easily solve this problem.
Thanks in advance.
I guess you meant
type triple = (int*int*string)
Also, you should avoid the ;, they are only necessary in the REPL. And you forgot to add end at the end of the let..in..end expression in the body of your function. Also avoid the ; or it won't compile (at least not in my version of SML).
You question is not entirely clear, and I am pretty sure there are many ways to do this. Alternatively you could try somewhat like:
fun timerrecord(record1:triple,record2:triple)=
case (record1, record2) of
((_,_,"AM"),(_,_,"PM")) => record1
| ((_,_,"PM"),(_,_,"AM")) => record2
| ((h1,m1,_),(h2,m2,_)) => if h1 < h2 then record1
else if h2 < h1 then record2
else if m1 < m2 then record1
else record2
There are few ways to do this. You can define record type in order to compile this function:
type recc = {hour:int, min:int, f:string};
and change your function signature to:
fun timerrecord(record1:recc,record2:recc)=
Or you can just by change function signature to:
fun timerrecord(record1:{hour:int, min:int, f:string},record2:{hour:int, min:int, f:string})=
ML is doing this by pattern matching:
fun timerRecord({hour = h1, min = m1, f = f1}, {hour = h2, min = m2, f = f2}) =
And your function will be :
fun timerRecord({hour = h1, min = m1, f = f1}, {hour = h2, min = m2, f = f2}) =
if (f1= "AM") andalso (f2="PM") then "t1 comes First"
else if(f1 = "PM") andalso (f2="AM") then "t2 comes First"
else if (h1 < h2) then "t1 comes First"
else if (h1 > h2) then "t2 comes First"
else if (m1 < m2) then "t1 comes First"
else "t2 comes First";

number_in_month exercise (Why x = x + 1 is considered bool in sml while x is int and how to say x = x + 1 correctly?)

Update: What I want to do with this code is to get a list of dates, year/month/day and a given number as a month, and check to see how many of the dates in the given list are in the same month as that given month. What I meant of x = x + 1 was x++ such as in java or C or C#. As the output I want x. if there is no match, 0 and for any match x = x + 1
So this is my code,
fun number_in_month (Dlist : (int * int * int) list, Month : int, x : int) =
if null Dlist then x
else if #2 (hd Dlist) = Month then x = x + 1 andalso number_in_month (tl(Dlist), Month, x)
else number_in_month ((tl(Dlist)), Month, x)
and it gives me error:
Error: types of if branches do not agree [tycon mismatch]
then branch: int
else branch: bool
in expression:
if null Dlist
then x
else if (fn <rule>) (hd <exp>) = Month
then (x = <exp> + <exp>)
andalso (number_in_month (<exp>,<exp>,<exp>))
else number_in_month (tl <exp>,Month,x)
I really don't get it why sml is considering x = x + 1 of type bool. I'd be really happy if someone could tell me how can I correctly say x = x + 1 in sml.
Thanks a lot in advance.
Saying x = x + 1 in Standard ML, you need to clarify what you intend to say, because clearly x = x + 1 means something you don't intend. What it means is "Compare x with x + 1 and say if they are equal" (which they never will be of any integer).
What I suppose you want to achieve is "update x to its successor", which is not possible without the use of reference types, which I discourage since they are not immutable and functional. The way you usually update something functionally is by passing an updated value to a function that eventually returns it. (Using function arguments as accumulating variables, so it feels as if it's the same variables that update their value e.g. upon each recursive call.)
Another thing I recommend that you do is use pattern matching instead of if-then-else. For example, you know that the list is empty if it matches []. Since the result of your computation is not a boolean, you cannot use "... andalso ..." -- I suspect you do this because you "want to do two things at once, and andalso smells like "doing something and also doing something else", but this would be a misconception. You can do this (using e.g. ; or before), but you would lose your result because these operators deal with side-effects and discard the main effect of one of their operands, so it is not what you want at this point.
Here is my stab in the dark at what you intended, written using pattern matching:
fun number_in_month ([], _, x) = x
| number_in_month ((one,two,three)::dlist, month, x) =
if two = month then number_in_month(dlist, month, x+1)
else number_in_month(dlist, month, x)
Modified: You can also do this without tail-recursion
fun number_in_month([], _) = 0
| number_in_month((_,month1,_)::dlist, month2) =
if month1 = month2 then 1 + number_in_month(dlist, month2)
else number_in_month(dlist, month2)
Or written differently:
fun number_in_month([], _) = 0
| number_in_month((_,month1,_)::dlist, month2) =
(if month1 = month2 then 1 else 0) + number_in_month(dlist, month2)
Or using list combinators:
fun counter(n1,n2) = if n1 = n2 then 1 else 0
fun number_in_month(dlist, month2) =
foldl (fn ((_,month1,_),count) => counter(month1,month2) + count) 0 dlist
Or using reference, as you asked for, even though I discourage this:
fun number_in_month (dlist, month2) =
let val count = ref 0
fun loop [] = !count (* the value inside the ref-cell *)
| loop ((_,month1,_)::dlist) =
if month1 = month2 then (count := !count + 1 ; loop dlist)
else loop dlist
in loop dlist end
As you can see, some complexity is added because I wish to create the ref-cell within the function, but I cannot create a new ref-cell upon every recursive call. So I create a helper function that is recursive and let it have the argument that changes during recursion (it can just inherit month2 and count from the parent scope of number_in_month. When recursion ends (base case), I choose to return the value within the ref-cell (using Standard ML's slightly obscure syntax for dereferencing).
Don't make it a habit of using ref-cells before you master the functional way. Otherwise you are back to coding imperatively in a language that makes this habit ugly. :)