\$\begingroup\$

Haskell / Standard ML, 56 bytes

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 t and t1 don't matter as the arguments aren't used in the function body. 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 returns 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 are 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 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 are many more differences, but those are the only 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 not a 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 immediately forgets it again, as it does not occur in the function body. Then the body print"treat" is executed which prints treat (without enclosing " , 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 . 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