# Language basics SCL is a functional programming language that is based on [lambda calculus]. Lambda calculus is a minimal but still Turing complete language with three constructions: * *Variables* * *Function applications* * *Function definitions* (lambda terms) These are also the most central elements of SCL and most of the other constructions are only syntactic sugar on top of lambda calculus. SCL syntax is very close to the syntax of [Haskell] programming language and many tutorials on Haskell apply also to SCL. The main difference between the languages is the evaluation strategy: Haskell evaluates terms lazily, SCL strictly. Unlike Haskell, SCL allows side-effects during function application, but controls them with effect typing. In this respects, it behaves similarly to [ML] or [OCaml]. SCL inherits the following philosophy from Haskell and other programming languages in functional paradigm: * Avoid stateful programming * Express mathematical problems in mathematical syntax * Expressive types prevent runtime errors [lambda calculus]: http://en.wikipedia.org/wiki/Lambda_calculus [Haskell]: https://www.haskell.org/ [ML]: http://en.wikipedia.org/wiki/ML_(programming_language) [OCaml]: https://ocaml.org/ This section gives a walkthrough for the most importatant constructs of SCL language. ## Literals SCL supports the following types of constant expressions: **Integers** 3423 **Floating point numbers** 1.2 2.6e-4 **String literals** SCL supports single-line strings (enclosed in quotes) "Single line text" "Text\nwith\nmultiple lines" and multi-line strings (enclosed in triple quotes) """Text with multiple lines""" Single-line strings may contain escaped characters (`\n` line feed, `\t` tabulator, `\r` carriage return, `\uxxxx` unicode character, `\` the character without the first `\`). **Character literals** 't' '\'' **Boolean constants** are written as `True` and `False` although they are not technically literals (but constructors). ## Identifiers Variable and constant names start with lower case letter followed by letters, digits, `_` and `'`. It customary to write multi-word concepts with camel case convention, for example `printError` or `importA5Model`. The following names are reserved and cannot be used as identifiers: `as`, `by`, `class`, `data`, `deriving`, `do`, `effect`, `else`, `enforce`, `extends`, `forall`, `hiding`, `if`, `import`, `importJava`, `in`, `include`, `infix`, `infixl`, `infixr`, `instance`, `let`, `match`, `mdo`, `rule`, `select`, `then`, `transformation`, `type`, `when`, `where`, `with`. Identifiers starting with upper case letter are *constructors* and they can be defined only together with the new data types. Examples: `True`, `False` and `Nothing`. ## Function applications A function is applied by writing the function and its parameters consecutively. sin pi max 2 5 A parameter needs to be closed in parenthesis if it is not a variable, literal, or an expression starting with `if`, `let`, `do`, etc. sqrt (x*x + y*y) atan2 (sin a) (cos a) For example sqrt x*x + y*y is evaluated as (sqrt x)*x + y*y because the function application has higher precedence than any binary operator. Parentheses are also needed around negation sin (-1.42) because otherwise the expression is tried to compile as sin - 1.42 causing a compilation error because `sin` and `1.42` are not compatible for subtraction. ## Binary operators Binary operators are normal functions that are just written between their parameters: 1 + 2 Each binary operator can be converted into ordinary function by putting parentheses around it (+) 1 2 Similarly an ordinary function can be converted into binary operator by putting backticks (\`) around it. 3.4 `max` 4.5 Binary operators have precedences that determines how multiple consecutive binary operators are compiled. For example 1*2+3*4+5*6 is evaluated as ((1*2) + (3*4)) + (5*6) ## Variable definitions Variables are defined by syntax variableName = variableValue for example g = 9.80665 Defined variable values are available in the consecutive expressions: a = 13 b = 14 a*b ## Function definitions Functions are defined by writing a function application in the left-hand side of the equation: increaseByOne x = x+1 Defined functions are available in the consecutive expressions: increaseByOne 13 ## Conditional expressions Conditional expressions are written in the form: if then else The `else` branch is always mandatory. abs x = if x > 0 then x else -x ## Recursion A function definition can refer to itself. For example, the Euclidean algorithm for computing the greatest common divisor of two integers can be written as: gcd a b = if a > b then gcd b a else if a == 0 then b else gcd (b `mod` a) a ## Local definitions Variable and function definitions can be written as a part of larger expression. There are three language constructs for this purpose: let in do where They are quite similar and it is usually just a stylistic choice which one to use. If you are only defining local variables that are needed in a subexpression and their computation does not have side-effects (or has only reading effects), the most natural choice is `let`-construct that allows you to define variables between `let` and `in` and used the variables in the expression following `in`: ~~~ distance (x1,y1) (x2,y2) = let dx = x1-x2 dy = y1-y2 in sqrt (dx*dx + dy*dy) ~~~ Let-expressions can be freely embedded in other expressions: ~~~ """ Finds a root of f given neg and pos with assumption that f neg < 0 and f pos > 0 """ bisectionMethod f neg pos = let middle = (neg+pos)*0.5 in if abs (neg-pos) < 1e-9 then middle else let middleVal = f middle in if middleVal < (-1e-9) then bisectionMethod f middle pos else if middleVal > 1e-9 then bisectionMethod f neg middle else middle ~~~ Another construction allowing local variable bindings is `do`. The value of the whole `do`-expression is determined by the last expression in the `do`-block. This construct should be used when there are side-effects involved and you want to mix variable bindings with function applications that ignore their result: ~~~ createModel parent name = do model = newResource () claim model L0.InstanceOf SIMU.Model claimRelatedValue model L0.HasName name claim model L0.PartOf parent model ~~~ The final binding construction is `where` that locates variable definitions after the position the variables are used. It differs from `let` and `do` because it does not define an expression but is always related to some other definition. The benefit is that the same `where` -block can be used by multiple different guarded definitions: ~~~ """ Returns all solutions of the quadratic equation a*x^2 + b*x + c = 0. """ solveQuadratic :: Double -> Double -> Double -> [Double] solveQuadratic a b c | discriminant < 0 = [] | discriminant > 0 = let sqrtDisc = sqrt discriminant in [ (-b-sqrtDisc)/(2*a) , (-b+sqrtDisc)/(2*a) ] | otherwise = [ -b / (2*a) ] where discriminant = b*b - 4*a*c ~~~ ## Functions taking other functions as parameters In SCL, functions are ordinary values that can be stored to variables and manipulated. For example, writing only the function name to the console produces: > sin Double> We can define for example a numerical derivative operation epsilon = 1e-9 der f x = (f (x + epsilon) - f (x - epsilon)) / (2*epsilon) Now, > der sin 0 1.0 > der exp 1 2.7182818218562943 ## Anonymous function definitions Functional style of programming favors lots of small functions. Giving a name for all of them becomes quickly tedious and therefore functions can be defined also anonymously. For example \x -> x+1 defines a function that increases its parameter by one. Thus (\x -> x+1) 13 returns `14`. Assuming that the function `der` is defined as above > der (\x -> x*x) 2 4.000000330961484 ## Partial function application It is possible to give a function less parameters that it accepts: > der sin Double> Such a partial application creates a function that expects the missing parameters: > myCos = der sin > myCos 0 > myCos pi -1.000000082740371 It is possible to partially apply also binary operators giving only one of its parameters. Such an application must always be enclosed in parentheses lessThanOne = (< 1) greaterThanOne = (1 <) ## Pattern matching The constructors are special kind of values and functions that can be used in the left-hand side of the function and value definitions. Most common constructors are the tuple constructors `()`, `(,)`, `(,,)`, ...: toPolarCoordinates (x,y) = (sqrt (x*x + y*y), atan2 y x) toRectangularCoordinates (r,angle) = (r*cos angle, r*sin angle) Other constructors are used like functions, but the name of the constructor is capitalized, for example `Just` and `Nothing`: fromMaybe _ (Just v) = v fromMaybe default Nothing = default This example demonstrates also some other features. A function can be defined with multiple equations and the first matching equation is used. Also, if some parameter value is not used, it may be replaced by `_`. ## Indentation