fun putStr x=print"treat";val main=();main=putStr"trick"
Haskell view
The semicolons allow multiple declarations in one line and act like linebreaks, so we get
fun putStr x=print"treat"
val main=()
main=putStr"trick"
A Haskell program is executed by calling the main function, so in the last row putStr"trick" is executed which just prints trick.
The first two rows are interpreted as function declarations following the pattern <functionName> <argumentName1> ... <argumentNameN> = <functionBody>. So in the first row a function named fun is declared which takes two arguments named putStr and x and the function body print"treat". This is a valid Haskell function with type fun :: t -> t1 -> IO (), meaning it takes an argument of an arbitrary type t and a second one of some type t1 an then returns an IO-action. The types don't matter as the arguments aren't used in the function body and the IO-action type results from print"treat", which prints "treat" to StdOut (notice the ", that's why putStr instead of print is used in main). However as it's only a function declaration, nothing is actually printed as fun is not called in main.
The same happens in the second line val main=();, a function val is declared which takes an arbitrary argument named main and return unit, the empty tuple (). It's type is val :: t -> () (Both the value and the type of unit are denoted with ()).
Try it on Ideone.
Standard ML view
Standard ML is a primarily functional language with a syntax related to, but not the same as Haskell. In particular, function declarations must be prefixed with the keyword fun if they take any arguments, and the keyword val if they don't. Also it's possible to have an expression at top level (meaning not inside any declaration) which is then executed when the program is run. (In Haskell writing 1+2 outside a declaration throws a naked expression at top level-error). Finally the symbol for testing equality is = instead of == in Haskell. (There many more differences, but those are the ones that matter for this program.)
So SML sees two declarations
fun putStr x=print"treat";
val main=();
followed by an expression
main=putStr"trick"
which is then evaluated. To determine whether main equals putStr"trick", both sides have to be evaluated and both must have the same type as SML (as well as Haskell) is statically typed.
Let us first have a look at the right side: putStr is no library function in SML, but we declared a function named putStr in the line fun putStr x=print"treat"; - it takes an argument x (this is the string "trick" in our case) and forgets about it again, as it does not occur in the function body. Then the body print"treat" is executed which prints treat (without enclosing ", so SML's print is different from Haskell's print). print has the type string -> unit, so putStr has the type a -> unit and therefore putStr"trick" has just type unit.
So in order to be well-typed, main must have type unit too. The value for unit is in SML the same as in Haskell (), so we declare val main=(); and everything is well-typed.
Try it on codingground.
Note: The output in the console is
val putStr = fn : 'a -> unit
val main = () : unit
treatval it = true : bool
because in SML\NJ the value and type of every statement is displayed after each declaration. So first the types of putStr and main are shown, then the expressions gets evaluated causing treat to be printed, then the value of the expression (true as both sides of = are ()) is bound to the implicit result variable it which is then also displayed.