Flix (programming language): Difference between revisions

Content deleted Content added
JorKadeen (talk | contribs)
m Add missing DOI
The Death of UFCS: https://github.com/flix/flix/issues/1500
 
(42 intermediate revisions by 19 users not shown)
Line 1:
{{about|the Flix programming language|other uses|Flix (disambiguation)}}
 
{{Orphan|date=December 2020}}
{{multiple issues|
{{excessive detail|date=December 2020}}
{{more citations needed|date=December 2020}}
{{Orphanprimary sources|date=December 2020}}
}}
{{Infobox programming language
| name = Flix
Line 7 ⟶ 12:
| typing = [[Hindley-Milner|inferred]], [[Static typing|static]], [[Strong and weak typing|strong]], [[structural typing|structural]]
| platform = [[Java virtual machine|JVM]]
| license = [[Apache License 2.0]].<ref name="license-github">{{cite web |url=https://github.com/flix/flix/blob/master/LICENSE.md|title=Apache License 2.0|date=27 July 2022 |via=[[GitHub]]}}</ref>
| website = {{URL|https://flix.dev/}}
| influenced_by = [[F_Sharp_F Sharp (programming_languageprogramming language)|F#]], [[Go_Go (programming_languageprogramming language)|Go]], [[Haskell_Haskell (programming_languageprogramming language)|Haskell]], [[OCaml]], [[Scala_Scala (programming_languageprogramming language)|Scala]]
| file_ext = {{Mono|.flix}}
}}
'''Flix''' is a [[functional programming|functional]], [[imperative programming|imperative]], and [[logic programming|logic]] [[programming language]] developed at [[Aarhus University]], with funding from the [[Danish_Council_for_Independent_ResearchDanish Council for Independent Research|Independent Research Fund Denmark]],<ref>{{cite web |title=Forskningsprojekter |url=https://dff.dk/forskningsprojekter?SearchableText=functional+and+declarative+logic+programming&period%3Alist=all&instrument%3Alist=all&filed_method%3Alist=all |website=Danmarks Frie Forskningsfond |language=da}}</ref>, and by a community of [[open source]] contributors.<ref>{{cite web |title=Flix Authors |url=https://github.com/flix/flix/blob/master/AUTHORS.md |website=GitHub |date=27 July 2022 |language=en}}</ref>. The Flix language supports [[algebraic data types]], [[pattern matching]], [[parametric polymorphism]], [[currying]], [[higher-order functionsfunction]]s, [[extensible records]],<ref>{{cite journal |last1=Leijen |first1=Daan |title=Extensible records with scoped labels |journal=Trends in Functional Programming}}</ref>, [[Communicating_sequential_processesCommunicating sequential processes|channel and process-based concurrency]], and [[tail call elimination]]. Two notable features of Flix are its type and effect system<ref name="oopsla2020a">{{cite journal |last1=Madsen |first1=Magnus |last2=van de Pol |first2=Jaco |title=Polymorphic Types and Effects with Boolean Unification |journal=Proceedings of the ACM on Programming Languages (OOPSLA|date=13 November 2020) |datevolume=20204 |issue=OOPSLA |pages=1–29 |doi=10.1145/3428222|s2cid=227044242 |doi-access=free }}</ref> and its support for first-class Datalog constraints.<ref name="oopsla2020b">{{cite journal |last1=Madsen |first1=Magnus |last2=Lhoták |first2=Ondřej |title=Fixpoints for the Masses: Programming with First-class Datalog Constraints |journal=Proceedings of the ACM on Programming Languages |date=13 November 2020 |volume=4 |issue=OOPSLA |pages=125:1–125:28 |doi=10.1145/3428193|s2cid=227107960 |doi-access=free }}</ref>.
 
The Flix type and effect system supports [[Hindley–Milner_type_systemHindley–Milner type system|Hindley-Milner]]-style [[type inference]]. The system separates pure and impure code: if an expression is typed as pure then it cannot produce an effect at run-time. Higher-order functions can enforce that they are given pure (or impure) function arguments. The type and effect system supports [[effect polymorphism]]<ref>{{cite journalbook |last1=Lucassen |first1=J. M. |last2=Gifford |first2=D. K. |title=Polymorphic effect systems |journal=Proceedings of the 15th ACM SIGPLAN-SIGACT Symposiumsymposium on Principles of Programmingprogramming Languageslanguages - POPL '88 |chapter=Polymorphic effect systems |date=1988 |pages=47–57 |doi=10.1145/73560.73564|isbn=0897912527 |s2cid=13015611 |doi-access=free }}</ref><ref>{{cite journal |last1=Leijen |first1=Daan |title=Koka: Programming with Row Polymorphic Effect Types |journal=Electronic Proceedings in Theoretical Computer Science |date=5 June 2014 |volume=153 |pages=100–126 |doi=10.4204/EPTCS.153.8|arxiv=1406.2061 |s2cid=14902937 }}</ref> which means that the effect of a higher-order function may depend on the effect(s) of its argument(s).
 
Flix supports [[Datalog]] programs as [[First-class_citizenclass citizen|first-class]] values. A Datalog program value, i.e. a collection of Datalog facts and rules, can be passed to and returned from functions, stored in data structures, and composed with other Datalog program values. The [[Minimal model program|minimal model]] of a Datalog program value can be computed and is itself a Datalog program value. In this way, Flix can be viewed as a [[metaprogramming|meta programming]] language for Datalog. Flix supports [[Stratification_Stratification (mathematics)#In_mathematical_logicIn mathematical logic|stratified negation]] and the Flix compiler ensures stratification at compile-time.<ref name="Programming Flix - Fixpoints">{{cite web |title=Programming Flix - Fixpoints |url=https://doc.flix.dev/fixpoints/ |website=flix.dev}}</ref>. Flix also supports an enriched form of Datalog constraints where predicates are given [[Lattice_Lattice (order)|lattice]] semantics.<ref>{{cite journal |last1=Madsen |first1=Magnus |last2=Yee |first2=Ming-Ho |last3=Lhoták |first3=Ondřej |title=From Datalog to flix: a declarative language for fixed points on lattices |journal=ACM SIGPLAN Notices |date=August 2016 |volume=51 |issue=6 |pages=194–208 |doi=10.1145/2980983.2908096}}</ref><ref>{{cite journalbook |last1=Madsen |first1=Magnus |last2=Lhoták |first2=Ondřej |title=Safe and sound program analysis with Flix |journal=Proceedings of the 27th ACM SIGSOFT International Symposium on Software Testing and Analysis -|chapter=Safe ISSTAand 2018sound program analysis with Flix |date=2018 |pages=38–48 |doi=10.1145/3213846.3213847|isbn=9781450356992 |s2cid=49427988 }}</ref><ref>{{cite journal |last1=Keidel |first1=Sven |last2=Erdweg |first2=Sebastian |title=Sound and reusable components for abstract interpretation |journal=Proceedings of the ACM on Programming Languages |date=10 October 2019 |volume=3 |issue=OOPSLA |pages=1–28 |doi=10.1145/3360602|s2cid=203631644 |doi-access=free }}</ref><ref>{{cite book |last1=Gong |first1=Qing |title=Extending Parallel Datalog with Lattice |publisher=Pennsylvania State University}}</ref>.
 
== Overview ==
 
Flix is a [[programming language]] in the [[Standard ML|ML]]-family of languages. Its type and effect system is based on [[Hindley–Milner_type_systemHindley–Milner type system|Hindley-Milner]] with several extensions, including [[row polymorphism]] and [[Unification_Unification (computer_sciencecomputer science)#E-unification|Boolean unification]]. The syntax of Flix is inspired by [[Scala (programming language)|Scala]] and uses short [[Reserved_wordReserved word|keywords]] and [[curly braces]]. Flix supports [[Uniform_Function_Call_Syntax|uniform function call syntax]] which allows a function call <code>f(x, y, z)</code> to be written as <code>x.f(y, z)</code>. The concurrency model of Flix is inspired by [[Go_Go (programming_languageprogramming language)|Go]] and based on [[Communicating_sequential_processesCommunicating sequential processes|channels and processes]]. A process is a light-weight thread that does not share (mutable) memory with another process. Processes communicate over channels which are bounded or unbounded queues of immutable messages.
 
While many programming languages support a mixture of functional and imperative programming, the Flix type and effect system tracks the purity of every expression making it possible to write parts of a Flix program in a [[Purely_functional_programmingPurely functional programming|purely functional style]] with purity enforced by the effect system.
 
Flix programs compilescompile to [[JVM bytecode]] and are executable on the [[Java Virtual Machine]] (JVM).<ref>{{cite book |last1=Yee |first1=Ming-Ho |title=Implementing a Functional Language for Flix |date=2016-09-15 |publisher=University of Waterloo}}</ref>.
The Flix compiler performs [[whole program compilation]], eliminates polymorphism via [[monomorphization]],<ref>{{cite web |title=Monomorphise |url=http://mlton.org/Monomorphise |website=mlton.org}}</ref>, and uses [[tree shaking]] to remove [[unreachable code]].
Monomorphization avoids [[Value_type_and_reference_typeValue type and reference type|boxing]] of primitive values at the cost of longer compilation times and larger executable binaries. Flix has some support for interoperability with programs written in [[Java programming language|Java]].<ref>{{cite web |title=Programming Flix - Interoperability |url=https://doc.flix.dev/interoperability/ |website=flix.dev}}</ref>.
 
Flix supports [[tail call elimination]] which ensures that function calls in tail position never consume stack space and hence cannot cause the call stack to overflow.<ref>{{cite journalbook |last1=Madsen |first1=Magnus |last2=Zarifi |first2=Ramin |last3=Lhoták |first3=Ondřej |title=Proceedings of the 27th International Conference on Compiler Construction |chapter=Tail call elimination and data representation for functional languages on the Java virtual machine |journal=Proceedings of the 27th International Conference on Compiler Construction - CC 2018 |date=2018 |pages=139–150 |doi=10.1145/3178372.3179499|isbn=9781450356442 |s2cid=3432962 }}</ref>. Since the [[Java_bytecode_instruction_listingsJava bytecode instruction listings|JVM instruction set]] lacks explicit support for tail calls, such calls are emulated using a form of reusable stack frames.<ref>{{cite journalbook |last1=Tauber |first1=Tomáš |last2=Bi |first2=Xuan |last3=Shi |first3=Zhiyuan |last4=Zhang |first4=Weixin |last5=Li |first5=Huang |last6=Zhang |first6=Zhenrui |last7=Oliveira |first7=Bruno C. D. S. |titlechapter=Memory-Efficient Tail Calls in the JVM with Imperative Functional Objects |journaltitle=Programming Languages and Systems |series=Lecture Notes in Computer Science |date=2015 |volume=9458 |pages=11–28 |doi=10.1007/978-3-319-26529-2_2|isbn=978-3-319-26528-5 }}</ref>. Support for tail call elimination is important since all iteration in Flix is expressed through [[recursion]].
 
The Flix compiler disallows most forms of unused or redundant code, including: unused local variables, unused functions, unused formal parameters, unused type parameters, and unused type declarations, such unused constructs are reported as compiler errors.<ref>{{cite web |title=Redundancies as Compile-Time Errors |url=https://flix.dev/blog/redundancies-as-compile-time-errors/ |website=flix.dev}}</ref>. [[Variable shadowing]] is also disallowed. The stated rationale is that unused or redundant code is often correlated with erroneous code<ref>{{cite journal |last1=Engler |first1=D. |title=Using redundancies to find errors |journal=IEEE Transactions on Software Engineering |date=October 2003 |volume=29 |issue=10 |pages=915–928 |doi=10.1109/TSE.2003.1237172}}</ref>
 
A [[Visual Studio Code]] extension for Flix is available.<ref>{{cite web |title=flix - Visual Studio Marketplace |url=https://marketplace.visualstudio.com/items?itemName=flix.flix |website=marketplace.visualstudio.com |language=en-us}}</ref>. The extension is based on the [[Language Server Protocol]], a common interface between [[Integrated_development_environmentIntegrated development environment|IDEs]] and [[compilers]] being developed by [[Microsoft]].
 
Flix is [[Open-source_softwaresource software|open source software]] available under the [[Apache_LicenseApache License|Apache 2.0 License]].
 
== Examples ==
 
=== Hello Worldworld ===
 
The following program prints "[["Hello,_World World!"_program program|Hello World!]]" when compiled and executed:
 
<syntaxhighlight lang="Scalaflx">
def main(): Unit &\ ImpureIO =
Console.printLineprintln("Hello World!")
</syntaxhighlight>
 
The type and effect signature of the <code>main</code> function specifies that it has no parameters, returns a value of type <code>Unit</code>, and that the function has the IO effect, i.e. is impure. The <code>main</code> function is impure because it invokes <code>printLine</code> which is impure.
 
=== Algebraic Datadata Typestypes and Patternpattern Matchingmatching ===
 
The following program fragment declares an [[algebraic data type]] (ADT) named <code>Shape</code>:
 
<syntaxhighlight lang="Scalaflx">
enum Shape {
case Circle(IntInt32), // has circle radius
case Square(IntInt32), // has side length
case Rectangle(IntInt32, IntInt32) // has height and width
}
</syntaxhighlight>
Line 65 ⟶ 70:
The following program fragment uses [[pattern matching]] to destruct a <code>Shape</code> value:
 
<syntaxhighlight lang="Scalaflx">
def area(s: Shape): IntInt32 = match s {
case Circle(r) => 3 * (r * r)
case Square(w) => w * w
Line 73 ⟶ 78:
</syntaxhighlight>
 
=== Higher-Orderorder Functionsfunctions ===
 
The following program fragment defines a [[higher-order function]] named <code>twice</code> that when given a function <code>f</code> from <code>Int</code> to <code>Int</code> returns a function that applies <code>f</code> to its input two times:
 
<syntaxhighlight lang="Scalaflx">
def twice(f: IntInt32 -> IntInt32): IntInt32 -> IntInt32 = x -> f(f(x))
</syntaxhighlight>
 
We can use the function <code>twice</code> as follows:
 
<syntaxhighlight lang="Scalaflx">
twice(x -> x + 1)(0)
</syntaxhighlight>
 
Here the call to <code>twice(x -> x + 1)</code> returns a function that will increment its argument two times. Consequently,Thus the result of the entirewhole expression is <code>0 + 1 + 1 = 2</code>.
 
=== Parametric Polymorphismpolymorphism ===
 
The following program fragment illustrates a [[Parametric_polymorphismParametric polymorphism|polymorphic function]] that maps a function <code>f: a -> b</code> over a list of elements of type <code>a</code> returning a list of elements of type <code>b</code>:
 
<syntaxhighlight lang="Scalaflx">
def map(f: a -> b, l: List[a]): List[b] = match l {
case Nil => Nil
Line 100 ⟶ 105:
</syntaxhighlight>
 
The <code>map</code> function recursively traverses the list <code>l</code> and applies <code>f</code> to each element constructing a new list.
 
Flix supports type parameter elision hence it is not required that the type parameters <code>a</code> and <code>b</code> are explicitly introduced.
 
=== Extensible Recordsrecords ===
 
The following program fragment shows how to construct a [[Record_Record (computer_sciencecomputer science)|record]] with two fields <code>x</code> and <code>y</code>:
 
<syntaxhighlight lang="Scalaflx">
def point2d(): {x: IntInt32, y: IntInt32} = {x = 1, y = 2}
</syntaxhighlight>
 
Flix uses [[row polymorphism]] to type records. The <code>sum</code> function below takes a record that has <code>x</code> and <code>y</code> fields (and possibly other fields) and returns the sum of the two fields:
 
<syntaxhighlight lang="Scalaflx">
def sum(r: {x: IntInt32, y: IntInt32 | rest}): Int = r.x + r.y
</syntaxhighlight>
 
The following are all valid calls to the <code>sum</code> function:
 
<syntaxhighlight lang="Scalaflx">
sum({x = 1, y = 2})
sum({y = 2, x = 1})
Line 126 ⟶ 131:
</syntaxhighlight>
 
== Notable Featuresfeatures ==
 
=== Polymorphic Effectseffects ===
 
The Flix type and effect system separates pure and impure expressions.<ref name="oopsla2020a"/><ref>{{cite web |title=Programming Flix - Effects |url=https://doc.flix.dev/effects/ |website=flix.dev}}</ref><ref>{{cite web|title=Rust Internals - Flix Polymorphic Effects|date=15 November 2020 |url=https://internals.rust-lang.org/t/flix-polymorphic-effects/13395}}</ref>. A pure expression is guaranteed to be [[Referential_transparencyReferential transparency|referentially transparent]]. A pure function always returns the same value when given the same argument(s) and cannot have any (observable) side-effects.
 
For example, the following expression is of type <code>IntInt32</code> and ishas the empty effect set <code>Pure{}</code>, i.e. it is pure:
 
<syntaxhighlight lang="Scalaflx">
1 + 2 : IntInt32 &\ Pure{}
</syntaxhighlight>
 
whereas the following expression ishas the <code>ImpureIO</code> effect, i.e. is impure:
 
<syntaxhighlight lang="Scalaflx">
Console.printLineprintln("Hello World") : Unit &\ ImpureIO
</syntaxhighlight>
 
Line 148 ⟶ 153:
For example, the definition of <code>Set.exists</code> requires that its function argument <code>f</code> is pure:
 
<syntaxhighlight lang="Scalaflx">
// The syntax a -> Bool is short-hand for a -> Bool &\ Pure{}
def exists(f: a -> Bool, xs: Set[a]): Bool = ...
</syntaxhighlight>
Line 159 ⟶ 164:
For example, the definition of <code>List.foreach</code> requires that its function argument <code>f</code> is impure:
 
<syntaxhighlight lang="Scalaflx">
//def The syntaxforeach(f: a ~-> Unit is\ short-handIO, forxs: List[a ->]): Unit &\ ImpureIO
def foreach(f: a ~> Unit, xs: List[a]): Unit & Impure
</syntaxhighlight>
 
The requirement that <code>f</code> must be impure ensures that the code makes sense: It would be meaningless to call <code>List.foreach</code> with a pure function since it always returns <code>Unit</code>.
 
The type and effect is [[sound]], but not [[complete]]. That is, if a function is pure then it ''cannot'' cause an effect, whereas if a function is impure then it ''may'', but not necessarily, cause an effect. For example, the following expression is impure even though it cannot produce an effect at run-time:
 
<syntaxhighlight lang="Scalaflx">
if (1 == 2) Console.printLineprintln("Hello World!") else ()
</syntaxhighlight>
 
Line 176 ⟶ 180:
For example, the standard library definition of <code>List.map</code> is effect polymorphic:<ref>{{cite web |title=The Flix API - List|url=https://api.flix.dev/List |website=api.flix.dev}}</ref>
 
<syntaxhighlight lang="Scalaflx">
def map(f: a -> b &\ e, xs: List[a]): List[b] &\ e
</syntaxhighlight>
 
Line 184 ⟶ 188:
A higher-order function that takes multiple function arguments may combine their effects.
 
For example, the standard library definition of forward [[Function_composition_Function composition (computer_sciencecomputer science)|function composition]] <code>&gt;&gt;</code> is pure if both its function arguments are pure:<ref>{{cite web |title=The Flix API - Prelude |url=https://api.flix.dev/ |website=api.flix.dev}}</ref>
 
<syntaxhighlight lang="Scalaflx">
def >>(f: a -> b &\ e1, g: b -> c &\ e2): a -> c &\ (e1 and+ e2) = x -> g(f(x))
</syntaxhighlight>
 
The type and effect signature can be understood as follows: The <code>&gt;&gt;</code> function takes two function arguments: <code>f</code> with effect <code>e1</code> and <code>g</code> with effect <code>e2</code>. The effect of <code>&gt;&gt;</code> is effect polymorphic in the [[Logical conjunction|conjunction]] of <code>e1</code> and <code>e2</code>. If both are pure (their effect is true) then the overall expression is pure (true). Otherwise it is impure.
 
The type and effect system allows arbitrary booleanset expressions to control the purity of function arguments.
 
For example, it is possible to express a higher-order function <code>h</code> that accepts two function arguments <code>f</code> and <code>g</code> where the effects of which<code>f</code> atare mostdisjoint onefrom isthose of impure<code>g</code>:
 
<syntaxhighlight lang="Scalaflx">
def h(f: a -> b &\ e1, g: b -> c &\ (note2 e1- or e2)e1): Unit
</syntaxhighlight>
 
If <code>h</code> is called with a function argument <code>f</code> which is impure (false) thenhas the second argument must be pure (true). Conversely, if <code>fIO</code> is pure (true)effect then <code>g</code> maycannot behave pure (true) or impure (false). It is a compile-time error to callthe <code>hIO</code> with two impure functionseffect.
 
The type and effect system can be used to ensure that statement expressions are useful, i.e. that if an expression or function is evaluated and its result is discarded then it must have a side-effect. For example, compiling the program fragment below:
 
<syntaxhighlight lang="Scalaflx">
def main(): Unit &\ ImpureIO =
List.map(x -> 2 * x, 1 :: 2 :: Nil);
Console.printLineprintln("Hello World")
</syntaxhighlight>
 
causes a compiler error:
 
<syntaxhighlight lang="output">
-- Redundancy Error --------------------------------------------------
 
Line 224 ⟶ 228:
because it is non-sensical to evaluate the pure expression <code>List.map(x -> 2 * x, 1 :: 2 :: Nil)</code> and then to discard its result. Most likely the programmer wanted to use the result (or alternatively the expression is redundant and could be deleted). Consequently, Flix rejects such programs.
 
=== First-class Datalogdatalog Constraintsconstraints ===
 
Flix supports [[Datalog]] programs as first-class values.<ref name="oopsla2020b"/>.<ref>{{cite web |titlename="Programming Flix - Fixpoints |url=https:"//doc.flix.dev/fixpoints/ |website=flix.dev}}</ref><ref>{{cite journal |last1=Arntzenius |first1=Michael |last2=Krishnaswami |first2=Neel |title=Seminaïve evaluation for a higher-order functional language |journal=Proceedings of the ACM on Programming Languages |date=January 2020 |volume=4 |issue=POPL |pages=1–28 |doi=10.1145/3371090|s2cid=208305062 |doi-access=free }}</ref>. A Datalog program is a logic program that consists of a collection of unordered [[Fact|factsfact]]s and [[Horn_clauseHorn clause|rules]]. Together, the facts and rules imply a [[Minimal model program|minimal model]], a unique solution to any Datalog program. In Flix, Datalog program values can be passed to and returned from functions, stored in data structures, composed with other Datalog program values, and solved. The solution to a Datalog program (the minimal model) is itself a Datalog program. Thus, it is possible to construct pipelines of Datalog programs where the solution, i.e. "output", of one Datalog program becomes the "input" to another Datalog program.
 
The following edge facts define a graph:
 
<syntaxhighlight lang="Scalaflx">
Edge(1, 2). Edge(2, 3). Edge(3, 4).
</syntaxhighlight>
Line 236 ⟶ 240:
The following Datalog rules compute the [[transitive closure]] of the edge relation:
 
<syntaxhighlight lang="Scalaprolog">
Path(x, y) :- Edge(x, y).
Path(x, z) :- Path(x, y), Edge(y, z).
Line 243 ⟶ 247:
The minimal model of the facts and rules is:
 
<syntaxhighlight lang="Scalaflx">
Edge(1, 2). Edge(2, 3). Edge(3, 4).
Path(1, 2). Path(2, 3). Path(3, 4).
Line 249 ⟶ 253:
</syntaxhighlight>
 
In Flix, Datalog programs are values. The above program can be [[Domain-specific_languagespecific language|embedded]] in Flix as follows:
 
<syntaxhighlight lang="Scalaflx">
def main(): #{Edge(IntInt32, IntInt32), Path(IntInt32, IntInt32)} =
let f = #{
Edge(1, 2). Edge(2, 3). Edge(3, 4).
Line 267 ⟶ 271:
Since Datalog programs are first-class values, we can refactor the above program into several functions. For example:
 
<syntaxhighlight lang="Scalaflx">
def edges(): #{Edge(IntInt32, IntInt32), Path(IntInt32, IntInt32)} = #{
Edge(1, 2). Edge(2, 3). Edge(3, 4).
}
 
def closure(): #{Edge(IntInt32, IntInt32), Path(IntInt32, IntInt32)} = #{
Path(x, y) :- Edge(x, y).
Path(x, z) :- Path(x, y), Edge(y, z).
}
 
def mainrun(): #{Edge(IntInt32, IntInt32), Path(IntInt32, IntInt32)} = solve edges() <+> closure()
</syntaxhighlight>
 
The un-directed closure of the graph can be computed by adding the rule:
 
<syntaxhighlight lang="Scalaprolog">
Path(x, y) :- Path(y, x).
</syntaxhighlight>
Line 288 ⟶ 292:
We can modify the <code>closure</code> function to take a Boolean argument that determines whether we want to compute the directed or un-directed closure:
 
<syntaxhighlight lang="Scalaflx">
def closure(directed: Bool): #{Edge(IntInt32, IntInt32), Path(IntInt32, IntInt32)} =
let p1 = #{
Path(x, y) :- Edge(x, y).
Line 300 ⟶ 304:
</syntaxhighlight>
 
==== Type-safe Compositioncomposition ====
 
The Flix type system ensures that Datalog program values are well-typed.
Line 306 ⟶ 310:
For example, the following program fragment does not type check:
 
<syntaxhighlight lang="Scalaflx">
let p1 = Edge(123, 456).;
let p2 = Edge("a", "b").;
Line 312 ⟶ 316:
</syntaxhighlight>
 
because in <code>p1</code> the type of the <code>Edge</code> predicate is <code>Edge(IntInt32, IntInt32)</code> whereas in <code>p2</code> it has type <code>Edge(String, String)</code>. The Flix compiler rejects such programs as ill-typed.
 
==== Stratified Negationnegation ====
 
The Flix compiler ensures that every Datalog program value constructed at run-time is [[Stratification_Stratification (mathematics)#In_mathematical_logicIn mathematical logic|stratified]]. Stratification is important because it guarantees the existence of a unique minimal model in the presence of negation. Intuitively, a Datalog program is stratified if there is no recursion through negation,<ref>{{cite book |last1=Minker |first1=Jack |title=Foundations of deductive databases and logic programming |publisher=Morgan Kaufmann}}</ref>, i.e. a predicate cannot depend negatively on itself. Given a Datalog program, a [[cycle detection]] algorithm can be used to determine if it is stratified.
 
For example, the following Flix program contains an expression that cannot be stratified:
 
<syntaxhighlight lang="Scalaflx">
def main(): #{Male(String), Husband(String), Bachelor(String)} =
let p1 = Husband(x) :- Male(x), not Bachelor(x).;
Line 327 ⟶ 331:
</syntaxhighlight>
 
because the last expression constructs a Datalog program value whose [[precedence_graph_precedence graph (Datalog)|precedence graph]] contains a negative cycle: the <code>Bachelor</code> predicate negatively depends on the <code>Husband</code> predicate which in turn (positively) depends on the <code>Bachelor</code> predicate.
 
The Flix compiler computes the precedence graph for every Datalog program valued expression and determines its stratification at compile-time. If an expression is not stratified, the program is rejected by the compiler.
 
The stratification is sound, but conservative. For example, the following program is [[Type_systemType system#Static_type_checkingStatic type checking|unfairly rejected]]:
 
<syntaxhighlight lang="Scalaflx">
def main(): #{A(IntInt32), B(IntInt32)} =
if (true)
A(x) :- A(x), not B(x).
Line 343 ⟶ 347:
The type system conservatively assumes that both branches of the if expression can be taken and consequently infers that there may be a negative cycle between the <code>A</code> and <code>B</code> predicates. Thus the program is rejected. This is despite the fact that at run-time the <code>main</code> function always returns a stratified Datalog program value.
 
== Design Philosophyphilosophy ==
 
Flix is designed around a collection of stated principles:<ref>{{cite web |title=The Flix Programming Language - Principles |url=https://flix.dev/principles/ |website=flix.dev |accessdate=28 August 2020}}</ref>:
 
* [[Expression-oriented_programming_languageoriented programming language|Everything is an expression]]. Most Flix constructs, except for top-level declarations, are expressions that evaluate to values.
* [[Closed-world assumption]]. The Flix compiler assumes that the source code of the entire program is available at compile-time.
* Pure and impure code is separated. The type and effect system precisely captures whether an expression may produce an effect<ref>{{cite web |title=Taming Impurity with Polymorphic Effects |url=https://flix.dev/blog/taming-impurity-with-polymorphic-effects/ |website=flix.dev}}</ref>
Line 354 ⟶ 358:
The principles also list several programming language features that have been deliberately omitted. In particular, Flix lacks support for:
 
* [[Null_pointerNull pointer|Null values]]. Instead the use of the [[Option_typeOption type|Option]] data type is recommended.
* [[Type_conversionType conversion|Implicit coercions]]. Instead type conversions must be performed explicitly by the programmer.
* [[Reflection_Reflection (computer_programmingcomputer programming)|Reflection]]. The programmer cannot reflect over the structure of the program at run-time.
 
== References ==
 
<!-- Inline citations added to your article will automatically display here. See en.wikipedia.org/wiki/WP:REFB for instructions on how to add citations. -->
{{reflist}}
 
== External Linkslinks ==
 
* [https://flix.dev/ The Official Websitewebsite]
* [https://docgithub.com/flix.dev/flix TheFlix Programmingimplementation Flixsource Bookcode], hosted at [[GitHub]].
* [https://play.flix.dev/ The Flix Online Playground]
* [https://github.com/flix/flix The Flix Project on GitHub]
* [https://api.flix.dev/ The Flix Standard Library]
 
[[Category:Procedural programming languages]]
 
[[Category:Functional languages]]
[[Category:Procedural programming languages]]
[[Category:Logic programming languages]]
[[Category:High-level programming languages]]
[[Category:High-level programming languages]]