Merge pull request #1225 from influxdata/flux/types-grammar

Update Flux type grammar
pull/1232/head
Scott Anderson 2020-07-21 09:33:21 -06:00 committed by GitHub
commit ef18afb9c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 85 deletions

View File

@ -79,84 +79,3 @@ ExpressionStatement = Expression .
f()
a
```
## Named types
A named type can be created using a type assignment statement.
A named type is equivalent to the type it describes and may be used interchangeably.
```js
TypeAssignment = "type" identifier "=" TypeExpression .
TypeExpression = identifier
| TypeParameter
| ObjectType
| ArrayType
| GeneratorType
| FunctionType .
TypeParameter = "'" identifier .
ObjectType = "{" PropertyTypeList [";" ObjectUpperBound ] "}" .
ObjectUpperBound = "any" | PropertyTypeList .
PropertyTypeList = PropertyType [ "," PropertyType ] .
PropertyType = identifier ":" TypeExpression
| string_lit ":" TypeExpression .
ArrayType = "[]" TypeExpression .
GeneratorType = "[...]" TypeExpression .
FunctionType = ParameterTypeList "->" TypeExpression
ParameterTypeList = "(" [ ParameterType { "," ParameterType } ] ")" .
ParameterType = identifier ":" [ pipe_receive_lit ] TypeExpression .
```
Named types are a separate namespace from values.
It is possible for a value and a type to have the same identifier.
The following named types are built-in.
```js
bool // boolean
int // integer
uint // unsigned integer
float // floating point number
duration // duration of time
time // time
string // utf-8 encoded string
regexp // regular expression
bytes // sequence of byte values
type // a type that itself describes a type
```
When an object's upper bound is not specified, it is assumed to be equal to its lower bound.
Parameters to function types define whether the parameter is a pipe forward
parameter and whether the parameter has a default value.
The `<-` indicates the parameter is the pipe forward parameter.
###### Examples
```js
// alias the bool type
type boolean = bool
// define a person as an object type
type person = {
name: string,
age: int,
}
// Define addition on ints
type intAdd = (a: int, b: int) -> int
// Define polymorphic addition
type add = (a: 'a, b: 'a) -> 'a
// Define funcion with pipe parameter
type bar = (foo: <-string) -> string
// Define object type with an empty lower bound and an explicit upper bound
type address = {
;
street: string,
city: string,
state: string,
country: string,
province: string,
zip: int,
}
```

View File

@ -12,15 +12,35 @@ menu:
weight: 206
---
Flux contains many preassigned values. These preassigned values are defined in the source files for the various built-in packages.
When a built-in value is not expressible in Flux, its value may be defined by the hosting environment.
All such values must have a corresponding builtin statement to declare the existence and type of the built-in value.
```js
BuiltinStatement = "builtin" identifier ":" TypeExpression .
BuiltinStatement = "builtin" identifer ":" TypeExpression .
TypeExpression = MonoType ["where" Constraints] .
MonoType = Tvar | Basic | Array | Record | Function .
Tvar = "A" … "Z" .
Basic = "int" | "uint" | "float" | "string" | "bool" | "time" | "duration" | "bytes" | "regexp" .
Array = "[" MonoType "]" .
Record = ( "{" [Properties] "}" ) | ( "{" Tvar "with" Properties "}" ) .
Function = "(" [Parameters] ")" "=>" MonoType .
Properties = Property { "," Property } .
Property = identifier ":" MonoType .
Parameters = Parameter { "," Parameter } .
Parameter = [ "<-" | "?" ] identifier ":" MonoType .
Constraints = Constraint { "," Constraint } .
Constraint = Tvar ":" Kinds .
Kinds = identifier { "+" identifier } .
```
##### Example
```js
builtin from : (bucket: string, bucketID: string) -> stream
builtin filter : (<-tables: [T], fn: (r: T) -> bool) -> [T]
```

View File

@ -14,9 +14,10 @@ Any section that is not currently implemented is commented with a **[IMPL#XXX]**
**XXX** is an issue number tracking discussion and progress towards implementation.
{{% /note %}}
A _type_ defines the set of values and operations on those values.
Types are never explicitly declared as part of the syntax.
A **type** defines the set of values and operations on those values.
Types are never explicitly declared as part of the syntax except as part of a [builtin statement](#system-built-ins).
Types are always inferred from the usage of the value.
Type inference follows a Hindley-Milner style inference system.
## Union types
A union type defines a set of types.
@ -154,3 +155,47 @@ The generated values may be of any other type, but must all be the same type.
{{% note %}}
[IMPL#658](https://github.com/influxdata/platform/query/issues/658) Implement Generators types.
{{% /note %}}
#### Polymorphism
Flux types can be polymorphic, meaning that a type may take on many different types.
Flux supports let-polymorphism and structural polymorphism.
##### Let-polymorphism
Let-polymorphism is the concept that each time an identifier is referenced, it may take on a different type.
For example:
```js
add = (a,b) => a + b
add(a:1,b:2) // 3
add(a:1.5,b:2.0) // 3.5
```
The identifiers, `a` and `b`, in the body of the `add` function are used as both `int` and `float` types.
##### Structural polymorphism
Structural polymorphism is the concept that structures (objects in Flux) can be
used by the same function even if the structures themselves are different.
For example:
```js
john = {name:"John", lastName:"Smith"}
jane = {name:"Jane", age:44}
// John and Jane are objects with different types.
// We can still define a function that can operate on both objects safely.
// name returns the name of a person
name = (person) => person.name
name(person:john) // John
name(person:jane) // Jane
device = {id: 125325, lat: 15.6163, lon: 62.6623}
name(person:device) // Type error, "device" does not have a property name.
```
Objects of differing types can be used as the same type so long as they both contain the necessary properties.
Necessary properties are determined by the use of the object.
This form of polymorphism means that checks are performed during type inference and not during runtime.
Type errors are found and reported before runtime.