0
votes

I am currently learning sml but I have one question that I can not find an answer for. I have googled but still have not found anything.

This is my code:

fun diamond(n) =
  if(n=1) then (
    print("*")
  ) else (

    print("*")
    diamond(n-1)

  )

diamond(5);

That does not work. I want the code to show as many * as number n is and I want to do that with recursion, but I don't understand how to do that.

I get an error when I try to run that code. This is the error:

Standard ML of New Jersey v110.78 [built: Thu Aug 20 19:23:18 2015] [opening a4_p2.sml] a4_p2.sml:8.5-9.17 Error: operator is not a function [tycon mismatch] operator: unit in expression: (print "*") diamond /usr/local/bin/sml: Fatal error -- Uncaught exception Error with 0 raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27

Thank you

1
What IS your output?Academiphile
@Zabari I get an error. This is the error: Standard ML of New Jersey v110.78 [built: Thu Aug 20 19:23:18 2015] [opening a4_p2.sml] a4_p2.sml:8.5-9.17 Error: operator is not a function [tycon mismatch] operator: unit in expression: (print "*") diamond /usr/local/bin/sml: Fatal error -- Uncaught exception Error with 0 raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27zeeks

1 Answers

2
votes

You can do side effects in ML by using ';' It will evaluate whatever is before the ';' and discard its result.

   fun diamond(n) =
      if(n=1)
      then (print "*"; 1)
      else (print "*"; diamond(n-1));

    diamond(5);

The reason for the error is because ML is a strongly typed language that although you don't need to specify types explicitly, it will infer them based on environmental factors at compile time. For this reason, every evaluation of functions, statements like if else need to evaluate to an unambiguous singular type.

If you were allowed to do the following:

      if(n=1)
      then 1
      else print "*";

then the compiler will get a different typing for the then and else branch respectively. For the then branch the type would be int -> int whereas the type for the else branch would be int -> unit Such a dichotomy is not allowed under a strongly typed language.

As you need to evaluate to a singular type, you will understand that ML does not support the execution of a block of instructions as we commonly see in other paradigms which transposed to ML naively would render something like this:

....
    if(n=1)
    then (print "1"
          print "2"
         )
    else (print "3"
          diamond(n-1)
         )
...

because what type would the then branch evaluate to? int -> unit? Then what about the other print statement? A statement has to return a singular result(even it be a compound) so that would not make sense. What about int -> unit * unit? No problem with that except that syntactically speaking, you failed to communicate a tuple to the compiler.

For this reason, the following WOULD work:

fun diamond(n) =
  if(n=1)
  then (print "a", 1)  /* A tuple of the type unit * int */
  else diamond(n-1);

diamond(5);

As in this case you have a function of type int -> unit * int.

So in order to satisfy the requirement of the paradigm of strongly typed functional programming where we strive for building mechanisms that evaluate to one result-type, we thus need to communicate to the compiler that certain statements are to be executed as instructions and are not to be incorporated under the typing of the function under consideration. For this reason, you use ';' to communicate to the compiler to simply evaluate that statement and discard its result from being incorporated under the type evaluation of the function.

As far as your actual objective is concerned, following is a better way of writing the function, diamond as type int -> string:

fun diamond(n) =
  if(n=1)
  then "*"
  else "*" ^ diamond(n-1);

print( diamond(5) );

The above way is more for debugging purposes.