site/contents/learn-operators.md
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
----- content-type: "page" title: "Learn: Operators" ----- {@ _defs_.md || 0 @} Every min program needs _operators_ to: * Manipulate elements on the stack * Perform operations on data * Provide side effects (read/print to standard input/output/files, etc.) There are two types of operators: _symbols_ and _sigils_. _Symbols_ are the most common type of operator. A min symbol is a single word that is either provided by one of the predefined min {#link-page||reference||modules#} like `dup` or `.` or defined by the user. User-defined symbols must: * Start with a letter or an underscore (\_). * Contain zero or more letters, numbers and/or any of the following characters: `/ ! ? + * . _ -` It is possible to define operator symbols using the {#link-operator||lang||operator#} symbol. The following min program defines a new symbol called square that duplicates the first element on the stack and multiplies the two elements: ( symbol square (num :n ==> num :result) (n dup * @result) ) operator ;; Calculates the square of n. The {#link-operator||lang||operator#} symbol provides way to: * Specify the name of the symbol operator (**square** in this case) * Specify a signature to identify the type of the input and output values (in this case, the operator takes a numeric input value and produces a numeric output value). Also, note how inputs and outputs are captured into the `n` and `result` symbols in the signature quotation and then referenced in the body quotation. * Specify a quotation containing the code that the operator will execute. Also, symbol operator definitions can be annotated with documentation comments (starting with `;;` or wrapped in `#|| ... ||#`)) so that a help text can be displayed using the {#link-operator||lang||help#} symbol. Besides symbols, you can also define sigils. min provides a set of predefined _sigils_ as abbreviations for for commonly-used symbols. A sigil can be prepended to a double-quoted string or a single word (with no spaces) which will be treated as a string instead of using the corresponding symbol. For example, the following executes the command `ls -al` and pushes the command return code on the stack: !"ls -al"` Currently min provides the following sigils: ' : Alias for {#link-operator||lang||quote#}. \: : Alias for {#link-operator||lang||define#}. * : Alias for {#link-operator||lang||invoke#}. @ : Alias for {#link-operator||lang||bind#}. > : Alias for {#link-operator||lang||save-symbol#}. < : Alias for {#link-operator||lang||load-symbol#}. = : Alias for {#link-operator||lang||quote-bind#}. \# : Alias for {#link-operator||lang||quote-define#}. / : Alias for {#link-operator||dict||dget#}. % : Alias for {#link-operator||dict||dset#}. ? : Alias for {#link-operator||lang||help#}. ! : Alias for {#link-operator||sys||system#}. & : Alias for {#link-operator||sys||run#}. $ : Alias for {#link-operator||sys||get-env#}. Besides system sigils, you can also create your own sigils. Unlike system sigils however, user defined sigils: * have the same character restrictions as symbols * can only be prepended to double-quoted strings * can be unsealed, deleted, redefined, and sealed. Sigils can be a very powerful construct and a way to reduce boulerplate code: you can define a sigil to use as you would use any symbol which requires a single string or quoted symbol on the stack. Like symbols, sigils can be defined with the {#link-operator||lang||operator#} operator, like this: ( sigil j (string :json ==> a :result) (json from-json @result) ) operator This definition will add a `j` sigil that will process the follwing string as JSON code, so for example: j"{\"test\": true}" ...will push the following dictionary on the stack: {true :test} Also, sigil definitions can be annotated with documentation comments (starting with `;;` or wrapped in `#|| ... ||#`)`) so that a help text can be displayed using the {#link-operator||lang||help#} symbol. ## Auto-popping Typically, but not always, operators push one or more value to the stack. While this is typically the desired behavior, in some cases you may want to keep the stack clear so in these cases you can append a `!` character to any symbol to cause the symbol {#link-operator||lang||pop#} to be pushed on the stack immediately afterwards. "test" puts ;Prints "test" and pushes "test" on the stack. "test" puts! ;Prints "test" without pushing anything on the stack. ## Operator signatures When defining symbols and sigils witb the {#link-operator||lang||operator#} operator, you must specify a *signature* that will be used to validate and captuee input and output values: ( symbol square (num :n ==> num :result) (n dup * @result) ) operator In this case for example tbe `square` symbol expects a number on the stack, which will be captured to tbe symbol `n` and it will place a number on the stack which needs to be bound in the operator body to the symbol `result`. In a signature, a type expression must precede the capturing symbol. Such type expression can be: * One of the following shorthand symbols identifying a well-known {{m}} base type (see the {#link-page||reference||reference#} section for more information): `a`, `bool`, `null`, `str`, `int`, `num`, `flt`, `'sym`, `quot`, or `dict`. * A typed dictionary like `dict:module` or `dict:datastore`. * A type class (see below). * a union of types/typed dictionaries/type classes, like `str|int`. > %note% > Note > > If the operator you are defining doesn't require any input value or doesn't leave ang output value on the srack, simply don't put anything before or after the `==>` separator, respectively. For example, the signature of the {#link-operator||lang||puts!#} operator could be written like `(a ==>)`. ### Type classes Besides standard base types, you can define your own *type classes* to express custom constraints/validations for operator input and output values. Consider the following type class definition validating a quotation containing strings: ( typeclass strquot (quot :q ==> bool :o) (q (string?) all? @o) ) :: The {#link-operator||lang||operator#} operator can be used to define a symbol prefixed with `typeclass:` (`typeclass:strquot` in this case) corresponding to a type class that can be used in operator signatures in place of a type, like this: ( symbol join-strings (strquot :q ==> string :result) ( q "" (suffix) reduce @result ) ) This operator will raise an error if anything other than a quotation of strings is found on the stack. > %tip% > Tip > > `typeclass:`-prefixed symbols are just like ordinary shmbols: they are lexically scoped, they can be sealed, unsealed and deleted. ### Generics {{m}} supports generics in operator signatures. in other words, you can define a custom type alias on-the-fly directly in an operator signature, like this: ``` ( symbol add ((string|num|quot :t) :a t :b ==> t :result) ( (a type "str" ==) (a b suffix @result return) when (a type "num" ==) (a b + @result return) when (a type "quot" ==) (a b concat #result return) when ) ) :: ``` In this case, `t` is set to the type union `stribg|num|quot`, and the `add` method above can be use too sum two numbers or join two strings or quotations. Note that the value of `t` is evaluated to the type of the first value that is processed. In other words, the following programs will work as expected: 3 5 add ;outputs 8 "hello, " "world" ;outputs "hello, world" while tbe fullowing will raise an error, because the value of `t` from `num` to `quot` within the same operator use: 12 "test" add ;raises an error > %sidebar% > Generics vs type unions > > Generics allow to specify a type as a type union, but the type will remain the same one throughout the same operator call. > By contrast, using the same type union several times within the same signature allows different types to be used in the same call, and that is probably something you dont want! {#link-learn||quotations||Quotations#} |