Failing to catch an exception in SML due to syntax error - exception

I'm trying to add the mechanism of catching an exception after throwing it
previously in code , but I can't get it to compile :
Here's the code without exception handling - it compiles and works great :
fun calc(input : string ) : int =
let
val outStr = ref "someString"
val outInt = ref 0
in
(
outStr := replaceRomanDec(input); (* replace roman number with decimal *)
outInt := calcMyRomanExpression(!outStr)
);
(!outInt)
end;
But when I try to put handle and exception , here :
fun calc(input : string ) : int =
exception CalculatorParser
let
val outStr = ref "someString"
val outInt = ref 0
in
(
outStr := replaceRomanDec(input); (* replace roman number with decimal *)
outInt := calcMyRomanExpression(!outStr);
handle CalculatorParser => -1
);
(!outInt)
end;
I get :
stdIn:1761.2-1761.28 Error: syntax error: deleting EXCEPTION ID
- );
=
= (!outInt)
=
=
=
= end;
stdIn:1576.1-1757.2 Error: syntax error: deleting RPAREN SEMICOLON
-
I tried to add/remove a semicolon as was suggested in the error ,but nothing worked .
Any idea what's wrong ?
Kind regards

It seems that you have missunderstod how sequence (expr_1; expr_2; ...; expr_n) of expressions work.
First off, there is no need to first "group" the outStr and outInt in their own sequence, just to use that in another sequence.
Secondly, we don't need parenthesis around a sequence insice the in ... end part of a local declaration (let), as there is a derived form (syntactic sugar) to handle that.
Also, there is no need to add parenthesis around a "dereference".
So a simplified version looks like this.
fun calc (input : string ) : int =
let
val outStr = ref "someString"
val outInt = ref 0
in
outStr := replaceRomanDec input; (* replace roman number with decimal *)
outInt := calcMyRomanExpression (!outStr);
!outInt
end
The grammar for handle is:
exp ::= ... | exp handle match | ...
Thus, the left hand side of handle, must be an expression. You have placed it as the last part of a sequence (exp_1 ; expr_2; expr_3):
expr_1 => outStr := replaceRomanDec(input);
expr_2 => outInt := calcMyRomanExpression(!outStr);
expr_3 => handle CalculatorParser => -1
From the we see that there is not supplied an expression to the left of handle. Thus you get an syntax error.
Since the result of your exception handling is -1, I assume it is the calcMyRomanExpression that throws the CalculatorParser exception. A solution could thus be:
fun calc(input : string ) : int =
let
val outStr = ref "someString"
val outInt = ref 0
in
outStr := replaceRomanDec(input); (* replace roman number with decimal *)
outInt := (calcMyRomanExpression(!outStr) handle CalculatorParser => ~1);
!outInt
end
Also remember that minus one is ~1 in SML.
As I noted in a comment to your question, you really ought to stop using references when doing functional programming. If you need to use them, then you are almost always doing it wrong.
If you had kept it functional, then the code could have been as simple as:
fun calc1 input = (calcMyRomanExpression o replaceRomanDec) input
or even simpler
val calc2 = calcMyRomanExpression o replaceRomanDec

Related

ML-Error in using exceptions

I wrote a function for handling an exception if we got r2=0 and i2=0, but when I run the program I get this error:
operatii.ml:12: error: Type error in function application.
Function: = : ''a * ''a -> bool
Argument: (r2, 0.0) : real * real
Reason: Can't unify ''a to real (Requires equality type)
Found near
if r2 = 0.0 then raise ImpartitorulEsteNul else
(
(r2 * r1 - i1 * i2) / (r2 * r2 + i1 * i2),
(... * ... + ... * ...) / (... * ... + ... * ...)
)
Exception- Fail "Static Errors" raised
Here is my code:
infix %%%%;
exception ImpartitorulEsteNul;
fun (r1,i1) %%%% (r2:real,i2:real)=if r2=0.0 andalso i2=0.0 then raise ImpartitorulEsteNul
else ((r2*r1-i1*i2)/(r2*r2+i1*i2),(r2*i1+i1*i2)/(r2*r2+i1*i2));
It happens because values of type real can't be checked for equality with the normal = operator. This happens due to how floating-point numbers are represented inside a computer and, honestly, it's something I can't explain to someone else yet. However, the solution is simple. You have to use the Real.== equality operator:
infix %%%%;
infix ==;
(* Import just the == function from the Real structure. *)
(* I hope you can make sense out of this line. *)
val op == = Real.==;
exception ImpartitorulEsteNul;
fun (r1,i1) %%%% (r2:real,i2:real) =
if r2==0.0 andalso i2==0.0
then raise ImpartitorulEsteNul
else ((r2*r1-i1*i2)/(r2*r2+i1*i2),(r2*i1+i1*i2)/(r2*r2+i1*i2));

F# generics / function overloading syntax

I'm confused on how to label a function as generic without an explicit type declaration like ('a -> 'a)
let add a b = a + b
This gives us
val add : a:int -> b:int -> int
However we can then immediately call
add "Hello " "World!"
and now the value of add is
val add : a:string -> b:string -> string
val it : string = "Hello World!"
If we then call
add 2 3 // then we get
error: This expression was expected to have type string but here has type int
How do I ensure that a function works on all types that say have the function (+) defined
This is F#'s embarrassing skeleton in the closet.
Try this:
> let mapPair f (x,y) = (f x, f y)
val mapPair : f:('a -> 'b) -> x:'a * y:'a -> 'b * 'b
Fully generic! Clearly, function application and tuples work.
Now try this:
> let makeList a b = [a;b]
val makeList : a:'a -> b:'a -> 'a list
Hmmm, also generic. How about this:
> let makeList a b = [a + b]
val makeList : a:int -> b:int -> int list
Aha, as soon as I have a (+) in there, it becomes int for some reason.
Let's keep playing:
> let inline makeList a b = [a + b]
val inline makeList :
a: ^a -> b: ^b -> ^c list
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
Hmmm, interesting. Turns out, if I make the function inline, then F# does consider it generic, but it also gives it this weird when clause, and my generic parameters have this strange ^ symbol instead of the usual tick.
This strange syntax is called "statically resolved type parameters" (see here for a somewhat coherent explanation), and the basic idea is that the function (+) requires its arguments to have a static member (+) defined. Let's verify:
> let x = 0 :> obj
let y = 0 :> obj
let z = x + y
Script1.fsx(14,13): error FS0001: The type 'obj' does not support the operator '+'
> type My() =
static member (+)( a:My, b:My ) = My()
let x = My()
let y = My()
let z = x + y
val x : My
val y : My
val z : My
Now, the problem with this is that CLR does not support this kind of generic parameters (i.e. "any type, as long as it has such and such members"), so F# has to fake it and resolve these calls at compile time. But because of this, any methods that use this feature cannot be compiled to true generic IL methods, and thus have to be monomorphised (which is enabled by inline).
But then, it would be very inconvenient to require that every function that uses arithmetic operators be declared inline, wouldn't it? So F# goes yet another extra step and tries to fix these statically resolved generic parameters based on how they are instantiated later in the code. That's why your function turns into string->string->string as soon as you use it with a string once.
But if you mark your function inline, F# wouldn't have to fix parameters, because it wouldn't have to compile the function down to IL, and so your parameters remain intact:
> let inline add a b = a + b
val inline add :
a: ^a -> b: ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
If I understand you correctly, use inline:
let inline add a b = a + b
add 2 3 |> printfn "%A"
add "Hello " "World!" |> printfn "%A"
Print:
5
"Hello World!"
Link: http://ideone.com/awsYNI
Make it inline
let inline add a b = a + b
(*
val inline add :
a: ^a -> b: ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
*)
add "Hello " "World!"
// val it : string = "Hello World!"
add 2 3
// val it : int = 5

Standard ML exceptions

I have the following code:
- exception Negative of string;
> exn Negative = fn : string -> exn
- local fun fact 0 =1
| fact n = n* fact(n-1)
in
fun factorial n=
if n >= 0 then fact n
else
raise Negative "Insert a positive number!!!"
handle Negative msg => 0
end;
What is wrong with it?? I get the error:
! Toplevel input:
! handle Negative msg => 0
! ^
! Type clash: expression of type
! int
! cannot have type
! exn
How can I fix it? I want the function to return 0, by means of exceptions, if the user enters a negative number.
I am also wondering how to display a message when the user enters a negative number, since print() returns unit, but the rest of the function returns int;
The precedence of raise and handle is a bit weird in SML. What you have written groups as
raise ((Negative "...") handle Negative msg => 0)
Consequently, you need to add parentheses around the if to get the right meaning.
On the other hand, I don't understand why you raise an exception just to catch it right away. Why not simply return 0 in the else branch?
Edit: If you want to print something and then return a result, use the semicolon operator:
(print "error"; 0)
However, I would strongly advise against doing that inside the factorial function. It's better to keep I/O and error handling separate from basic computational logic.
Here is a number of ways you can fix your code:
local
fun fact 0 = 1
| fact n = n * fact (n-1)
in
(* By using the built-in exception Domain *)
fun factorial n =
if n < 0 then raise Domain else fact n
(* Or by defining factorial for negative input *)
fun factorial n =
if n < 0 then -1 * fact (-n) else fact n
(* Or by extending the type for "no result" *)
fun factorial n =
if n < 0 then NONE else SOME (fact n)
end

check if a tree is complete standard ml

I want to make a function in standard ml that checks if a tree is complete or not, the function somehow works, but its giving me the wrong type and a warning of non-exhaustive cases
The tree code:
datatype 'data tree =
EMPTY
| NODE of 'data tree * 'data * 'data tree;
fun isComplete EMPTY = true
| isComplete (NODE(x, y, z)) = if (x = EMPTY andalso z <> EMPTY) orelse (x <> EMPTY andalso z = EMPTY) then false else true;
Now the above function's type is: ''a tree -> bool but the required type is 'a tree -> bool
The warning I'm having is:
stdIn:169.8 Warning: calling polyEqual
stdIn:169.26 Warning: calling polyEqual
stdIn:169.45-169.47 Warning: calling polyEqual
stdIn:169.64-169.66 Warning: calling polyEqual
stdIn:124.1-169.94 Warning: match nonexhaustive
NODE (x,y,z) => ...
What is the problem I'm having?
EDIT:
Thanks to Michael, I fixed the code and now it works:
- fun isComplete EMPTY = true
| isComplete (NODE(EMPTY, _, EMPTY)) = true
| isComplete (NODE(NODE(x, y, z), _, NODE(a, b, c))) = true
| isComplete (EMPTY, _, NODE(x, y, z)) = false
| isComplete (NODE(x, y, z), _, EMPTY) = false;
The ''a tree -> bool type indicates that a is an equality type: it must be a type that supports testing with equals. Since you are using = and <> to test x and z, the tree data must support equality (even though you're not doing anything interesting with the values). This is the root of the polyEqual warning.
The nonexhaustive match warning is more puzzling. When I paste your datatype and function definitions into Moscow ML, I do not get a warning. I don't think I'd worry about it too much, as I'd expect fixing the type to also take care of the warning.
To get the desired type 'a tree -> bool, I'd suggest getting rid of the if in favor of pattern matching. E.g.:
fun isComplete EMPTY = true
| isComplete (NODE(EMPTY, _, EMPTY)) = true
| isComplete (NODE(EMPTY, _, NODE(x,y,z))) = false
| ... (* fill out the rest of the cases *)
I'll leave it to you to figure out the full set of cases, as this looks like homework.
Incidentally, I don't think your test for completeness is correct. Consider what happens when neither subtree is EMPTY: you call the tree complete without considering the contents. This doesn't have anything to do with the warnings you're seeing, though.
Concerning the polyEqual warning: in SML/NJ this warning is printed everytime you use this operator, but that doesn't mean your code is faulty. Here's a blog post about it, and in the comments someone explains why the warning is given: http://abstractfactory.blogspot.fr/2006/05/sml-hacking-tip-turn-off-polyequal.html

Scala Map, ambiguity between tuple and function argument list

val m = scala.collection.mutable.Map[String, Int]()
// this doesn't work
m += ("foo", 2)
// this does work
m += (("foo", 2))
// this works too
val barpair = ("bar", 3)
m += barpair
So what's the deal with m += ("foo" , 2) not working? Scala gives the type error:
error: type mismatch;
found : java.lang.String("foo")
required: (String, Int)
m += ("foo", 2)
^
Apparently Scala thinks that I am trying to call += with two arguments, instead of one tuple argument. Why? Isn't it unambiguous, since I am not using m.+= ?
Unfortunately a b (c, d, e, ..) desugars to a.b(c, d, e, ..). Hence the error.
Isn't it unambiguous, since I am not using m.+= ?
No, it isn't, because parenthesis can always be used when there are multiple arguments. For example:
List(1, 2, 3) mkString ("<", ", ", ">")
So you might ask, what multiple parameters? Well, the Scala API doc is your friend (or mine, at least), so I present you with:
scala> val m = scala.collection.mutable.Map[String, Int]()
m: scala.collection.mutable.Map[String,Int] = Map()
scala> m += (("foo", 2), ("bar", 3))
res0: m.type = Map(bar -> 3, foo -> 2)
In other words, += takes a vararg.
The preferred way to define map entries is to use the -> method. Like
m += ("foo" -> 2)
Which constructs a tuple. a -> b gets desugared to a.->(b). Every object in scala has a -> method.