X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scl.tutorial%2Fscl%2FTutorial%2F1.02%20Language%20basics.md;fp=bundles%2Forg.simantics.scl.tutorial%2Fscl%2FTutorial%2F1.02%20Language%20basics.md;h=82e575c26e554c18e0561f470ff64f6def2fdc9b;hb=39fd9bd29b18a2f7abe62fb13da3359b3618dda7;hp=0000000000000000000000000000000000000000;hpb=f024c0a7208e379a82f0ab51a71a123f9bb2a2bb;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scl.tutorial/scl/Tutorial/1.02 Language basics.md b/bundles/org.simantics.scl.tutorial/scl/Tutorial/1.02 Language basics.md new file mode 100644 index 000000000..82e575c26 --- /dev/null +++ b/bundles/org.simantics.scl.tutorial/scl/Tutorial/1.02 Language basics.md @@ -0,0 +1,357 @@ +# 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 +