git.iko.soy/rowtype-yoga/purescript-native
on 136cd21 help sign in
599 lines 15 kB history raw
1purescript
2==========
4[![Build Status](https://secure.travis-ci.org/paf31/purescript.png?branch=master)](http://travis-ci.org/paf31/purescript)
6A small strongly, statically typed compile-to-JS language with basic extensible records and type-safe blocks
8## Current Features
10- Full Type Inference
11- Higher Kinded Polymorphism
12- Support for basic Javascript types
13- Extensible records
14- Type-safe blocks with for/while/assignment etc.
15- Functions with multiple arguments
16- Pattern matching
17- Simple FFI
19## Try It!
21Try PureScript in the browser [here](http://tryps.functorial.com/).
23## License
25See the `LICENSE` file
27## Contributing
29Contributions are always encouraged! Please see `CONTRIBUTING.md` for guidelines.
31## Installation
33Install the Haskell Plaform, then `cabal install`
35## Usage
37The `psc` executable takes a list of PureScript source files as arguments and by default writes out its errors or output to the console.
39The following options are supported:
41 -o --output
42 Write the generated Javascript to the specified file
44 -e --externs
45 Write a list of externs declarations to the specified file in addition to generating Javascript output
47## Motivation
49I was looking for a simple functional language which would compile to JavaScript and have the following characteristics:
51- Generate simple readable Javascript
52- Provide the ability to compile to tight loops if necessary
53- Reasonable type system
54- Ideally, written in a programming language I would enjoy working in
55- Provides a simple interface to existing Javascript code
57I didn't find exactly what I was looking for, so I wrote PureScript. It doesn't have everything right now, but it should serve as a simple core on which to develop new ideas.
59PureScript is *not* designed to be a general-purpose programming language. The primary use case is as a generator for purely-functional core libraries, with the main application code written in another language.
61PureScript can also be seen as a trade-off between a theoretically ideal language and one which generates reasonably high performance code.
63## First Example
65The following code defines a `Person` data type and a function to generate a string representation for a `Person`:
67```haskell
68data Person = Person { name :: String, age :: Number }
70extern numberToString :: Number -> String
72showPerson :: Person -> String
73showPerson = \p -> case p of
74 Person o -> o.name ++ ", aged " ++ numberToString(o.age)
75```
77Line by line, this reads as follows:
79- `Person` is a data type with one constructor, also called `Person`
80 - The `Person` constructor takes an object with two properties, `name` which is a `String`, and `age` which is a `Number`
81- The `numberToString` function is written in Javascript, and converts a `Number` to its `String` representation
82- The `showPerson` function takes a `Person` and returns a `String`
83- `showPerson` works by case analysis on its argument `p`, first matching the constructor `Person` and then using string concatenation and object accessors to return its result.
85The generated Javascript looks like this:
87```javascript
88var Person = function (value) {
89 return { ctor: 'Person', value: value };
90};
92function showPerson(p) {
93 if (p.ctor === "Person") {
94 return p.value.name + ", aged " + itoa(p.value.age)
95 };
96 throw "Failed pattern match"
99```
101## Type System
103The type system defines the following types:
105- Primitive Types
106 - Number
107 - String
108 - Boolean
109- Arrays
110 - E.g. `[String]`, `[[Number]]`
111- Records
112 - E.g. `{ foo :: String, bar :: Number }`
113- Tagged Unions
114 - E.g. `data Foo a = Foo | Bar String`
115- Functions
116 - E.g. `Number -> String`
117 - E.g. `(Number, Number) -> Number`
118 - Functions can have zero or more arguments
119- Polymorphic types (for top level declarations only)
120 - E.g. `forall a. a -> a`
122## Primitive Types
124The three primitive types `String`, `Number` and `Boolean` correspond to their Javascript equivalents at runtime.
126PureScript supports the same binary and unary operations on primitive types as Javascript, with the following exceptions:
128- String concatenation is denoted `++` to differentiate it from numeric addition, `+`
129- PureScript's `==` and `!=` correspond to Javascript's strong equality tests `===` and `!==`
131Examples:
133```haskell
134num = 1 + 2 * 3
135str = "Hello, " ++ "World!"
136bool = 1 > 2 || true
137```
139## Arrays
141PureScript arrays correspond to Javascript arrays at runtime, but all elements must have the same type.
143Array literals look like Javascript array literals: `[1, 2, 3]`
145Array elements can be read using array index notation `arr[0]`
147## Records
149PureScript records correspond to Javascript objects.
151Record literals look like Javascript object literals: `{ foo: "Foo" }`
153Properties can be read by using dot notation: `o.foo`
155## Tagged Unions
157Tagged unions consist of one or more constructors, each of which takes zero or one arguments.
159Tagged unions can only be created using their constructors, and deconstructed through pattern matching (see later).
161For example:
163```haskell
164data Foo a = Foo | Bar String
166runFoo = \foo -> case foo of
167Foo -> "It's a Foo"
168Bar s -> "It's a Bar. The string is " ++ s
170runFoo Foo ++ runFoo (Bar "Test")
171```
173In the example, Foo is a tagged union type which has two constructors. It's first constructor `Foo` takes no argument, and it's second `Bar` takes one, which must be a String.
175`runFoo` is an example of pattern matching on a tagged union type to discover its constructor, and the last line shows how `Foo`s are constructed.
177## Functions
179Functions in PureScript can have zero or more arguments in general, just like in Javascript.
181Functions are introduced by using a backslash followed by a comma separated list of argument names:
183```haskell
184test1 = \a, b, c -> a + b + c
185```
187which would correspond to the Javascript `function test1(a, b, c) { return a + b + c; }`
189A function taking no arguments would look like this:
191```haskell
192test2 = \ -> 100
193```
195which would correspond to the Javascript `function test2() { return 100; }`
197Functions are applied by providing their arguments inside parentheses:
199```haskell
200test1(1, 2, 3)
201test2()
202```
204A special case is made in the case of functions with one argument. These functions can be applied without parentheses, and function application associates to the left:
206```haskell
207-- has type Number -> Number -> Number -> Number
208addThree = \a -> \b -> \c -> a + b + c
210-- has type Number -> Number -> Number
211addThree 1
213-- has type Number -> Number
214addThree 1 2
216-- has type Number
217addThree 1 2 3
218```
220## Polymorphic Types
222Expressions defined at the top level may have polymorphic types.
224Here is an example:
226```haskell
227identity = \x -> x
228```
230`identity` is inferred to have (polymorphic) type `forall t0. t0 -> t0`. This means that for any type `t0`, `identity` can be given a value of type `t0` and will give back a value of the same type.
232A type annotation can also be provided:
234```haskell
235identity :: forall a. a -> a
236identity = \x -> x
237```
239Functions may also be polymorphic in row types or type variables with other kinds (see "Kind System"):
241```haskell
242addProps = \o -> o.foo + o.bar
243```
245Here, `addProps` is inferred to have type `forall r. { foo :: Number, bar :: Number | r } -> Number`. That is, it can take any type which has properties `Foo` and `Bar`, and *any other record properties*.
247So, the following compiles:
249```haskell
250addProps { foo: 1, bar: 2, baz: 3 }
251```
253but the following does not:
255```haskell
256addProps { foo: 1 }
257```
259since the `bar` property is missing.
261Again, a type annotation can be provided if necessary.
263## Type Inference
265All types can be inferred, but annotations can optionally be provided.
267## Kind System
269There are two primitive kinds, the kind `*` of types and the kind `#` of rows. Higher kinded types are also supported. That is, a type variable can refer to not only a type or a row, but a type constructor, or row constructor etc.
271## Whitespace
273Syntax is whitespace sensitive. The general rule of thumb is that declarations which span multiple lines should be indented past the column on which they were first defined on their subsequent lines.
275That is, the following is valid:
277```haskell
278foo = bar(x) +
279 baz(x)
280```
282But this is not:
284```haskell
285foo = bar(x) +
286baz(x)
287```
289## Do Notation
291There is a keyword `do`, which does not have the same purpose as the `do` keyword in Haskell.
293`do` introduces a block. Blocks consist of statements, and must return a value of the same type on every branch of execution.
295The following types of statement are supported:
297- Variable introduction
298- Variable assignment
299- For loops
300- For-each loops
301- While loops
302- If-Then-Else statements
304Here is an example of a power function defined using a block:
306```haskell
307pow = \n, p -> do
308 var m = n
309 for i <- 0 until p:
310 m = m * n
311 return m
312```
314Blocks enable local mutation of their variables, but mutation is not allowed in general. The type system prevents mutable variables from escaping their scope.
316That is, while the example above is valid, the following does not compile:
318```haskell
319incr = \n -> do
320 n = n + 1
321 return n
322```
324The variable `n` is not mutable, and so the assignment in the first line of the `do` block is not allowed.
326This function can be rewritten as follows:
328```haskell
329incr = \n -> do
330 var m = n
331 m = m + 1
332 return m
333```
335## For Loops
337For loops look like this:
339```haskell
340total = do
341 var n = 0
342 for i <- 0 until 10:
343 n = n + i
344 return n
345```
347The bounds `0` and `10` are inclusive and exclusive respectively.
349## For-Each Loops
351For each loops loop over the elements in an array using the `Object.forEach` method. A polyfill may be required for some browsers:
353```haskell
354total = \arr -> do
355 var n = 0
356 foreach i in arr:
357 n = n + i
358 return n
359```
361## While Loops
363The syntax of a while loop is similar to a foreach loop:
365```haskell
366log2 = \n -> do
367 var count = 0
368 var m = n
369 while m > 1:
370 m = m / 2
371 count = count + 1
372 return count
373```
375## If-Then-Else Statements
377Else branches are optional, and may contain further `if` statements, just as in Javascript:
379```haskell
380collatz = \n -> do
381 var count = 0
382 var m = n
383 while m > 1:
384 if m % 2 == 0:
385 m = m / 2
386 else:
387 m = m * 3 + 1
388 count = count + 1
389 return count
390```
392## If-Then-Else Expressions
394The `if`, `then` and `else` keywords can also be used to create conditional expressions. In this case, the `else` block is always required.
396For example,
398```haskell
399conditional = if 2 > 1 then "ok" else "oops"
400```
402## Pattern Matching
404Pattern matching deconstructs a value to bring zero or more expressions into scope. Pattern matches are introduced with the `case` keyword.
406Pattern matches have the following general form
408```haskell
409case value of
410 pattern -> result
411 -- ...
412 pattern -> result
413```
415The following pattern types are supported:
417- Wildcard pattern
418- Literal patterns
419- Variable pattern
420- Array patterns
421- Record patterns
422- Named patterns
423- Guards
425Patterns need not be exhaustive. A pattern match failed exception will be thrown at runtime if no pattern matches the input.
427## Wildcard Patterns
429The wilcard `_` matches any input and brings nothing into scope:
431```haskell
432case x of
433 _ -> 0
434```
436## Literal Patterns
438Literal patterns are provided to match on primitives:
440```haskell
441case booleanValue of
442 true -> 0
443 false -> 1
445case stringValue of
446 "Foo" -> 0
447 _ -> 1
449case numericValue of
450 0 -> 0
451 _ -> 1
452```
454## Variable Pattern
456A variable pattern matches any input and binds that input to its name:
458```haskell
459case foo(x) of
460 result -> bar(result)
461```
463## Array Patterns
465Array patterns match an input which is an array, and bring its elements into scope.
467For example:
469```haskell
470f = \arr -> case arr of
471 [x] -> x
472 [x, y : xs] -> x * y + f(xs)
473 _ -> 0
474```
476Here, the first pattern only matches arrays of length one, and brings the first element of the array into scope.
478The second pattern matches arrays with two or more elements, and brings the first and second elements into scope, along with the remainder of the array as the variable `xs`.
480## Record Patterns
482Record patterns match an input which is a record, and bring its properties into scope.
484```haskell
485f = \o -> case o of
486 { foo = "Foo" } -> o.bar
487 _ -> 0
488```
490## Nested Patterns
492The patterns above can be combined to create larger patterns.
494For example:
496```haskell
497f = \o -> case o of
498 { arr = [x:_], take = "car" } -> x
499 { arr = [_,x:_], take = "cadr" } -> x
500 _ -> 0
501```
503## Named Patterns
505Named patterns bring additional names into scope when using nested patterns. Any pattern can be named by using the `@` symbol:
507```haskell
508f = \arr -> case arr of
509 a@[_,_:_] -> a
510 a -> a
511```
513Here, in the first pattern, any array with two or more elements will be matched and bound to the variable `a`.
515## Guards
517Guards are used to impose additional constraints inside a pattern using boolean-valued expressions, and are introduced with a pipe after the pattern:
519```haskell
520evens = \arr -> case arr of
521 [] -> 0
522 [x:xs] | x % 2 == 0 -> 1 + evens xs
523 [_:xs] -> evens xs
524```
526## Type Synonyms
528For convenience, it is possible to declare a synonym for a type using the `type` keyword. Type synonyms can include type arguments.
530For example:
532```haskell
533type Foo = { foo :: Number, bar Number }
535addFoo :: Foo -> Number
536addFoo = \o -> o.foo + o.bar
537```
538## Record Updates
540Properties on records can be updated using the following syntax: `o { key = value, ..., key = value }`
542For example, the following function increments the `foo` property on its argument:
544```haskell
545incr = \o -> o { foo = o.foo + 1 }
546```
548The generated Javascript assumes the existence of a method called `Object.extend` such that `Object.extend(o, p)` takes an object `o` and generates a shallow copy of `o` including the properties of `p`. A simple JQuery implementation of this specification is
550```haskell
551Object.prototype.extend = function(o, p) {
552 return $.extend({}, o, p);
553};
554```
556## Operators
558In addition to the standard operators, user-defined infix operators can be created by enclosing names in parentheses:
560E.g. to create a synonym for string concatenation:
562```haskell
563(<>) = \s1 -> \s2 -> s1 ++ s2
565greeting = "Hello" <> "World!"
566```
568Regular functions can be used as operators by enclosing their names in backticks:
570```haskell
571foo = \x -> \y -> x * y + y
573test = 10 `foo` 20
574```
576Fixity declarations can associate a precedence level, which is a natural number, to a user-defined operator, and specify which way it associates:
578```haskell
579infixl 5 <>
580infixr 7 %%
581```
583## Foreign Function Interface
585The `extern` keyword declares a value which is defined in Javascript, and its type:
587```haskell
588extern pow :: (Number, Number) -> Number
589```
591To declare a new type with no constructors, use `extern data` and provide the kind:
593```haskell
594extern data IO :: * -> *
596extern console :: {
597 log :: String -> IO {}
599```