The Ficus computer programming language is a purely functional general purpose programming language that is backward compatible to the Elm compiler version 0.19.1 syntax but is extended to be able to generate native code, Web Assembly, or JavaScript, applications for Windows, macOS, Linux, iOS, and Android (or Android-like mobile OS's) as well as "front-end" web pages and "back-end" web servers using either JavaScript or Web Assembly for web pages. For desktop applications, Ficus can generate Graphics User Interface (GUI) applications by leveraging its capability of interfacing to WebKit/WebView through generated Virtual DOM using HTML.
The motivation for the creation of this not-so-new syntax language is to extend the work by Evan Czaplicki on the Elm Programming language so that Elm doesn't fade into obscurity as it is very much as it advertises: "A delightful language for reliable web applications." except to extend it from being a domain specific language for generating web pages to use as a general purpose language. It is in particular worth preserving for the following reasons:
- It is one of the few pure functional languages (such as are Haskell and PureScript) with strong static Type safety and Type Inference but with a very simple syntax with a minimum of keywords and operators to learn, such that typical programmers can become quite proficient in a matter of a few weeks. The two main concepts that an imperative/Object Oriented Programming programmer must learn are the ideas of using implicit and explicit function recursion to replace imperative loops, and how to use the systems supporting making handling "side effects" (functions that modify the environment and thus are not "pure" in not producing the same effect or returning the same result for every function call) into pure function calls from the aspect of the programmer. This last includes such things as printing to a terminal console, inputing text from terminal consoles, getting represetations of time from the operating system, producing pseudo-random numbers, accessing file hierarchy names and accessing files within that hierarchy, accessing environment variables and program arguments, etc.
- As it is a pure functional language not allowing mutation that the programmer can see, it is at least as safe as languages built around Type and Memory safety such as the Rust programmingn Language, but without the complex syntax needed to express the control of lifetimes in spite of mutation and sharing of variables that are complex structures.
- Since it is non-deferred/non-lazy/"strict" by default, it doesn't have the compllications of Haskell in not lifting every variable by default to be evaluated (and the result stored) only when actually used, although deferred execution can be implemented in order to inject lazy evaluation when required.
In honor of Elm, which is named after a large genus of trees, Ficus is named after another large genus of trees (the genus of fig trees), but with the significance of a name starting with F for "Functional" and "Ficus" rather than E for Elm in it emphasizes that Ficus is a functional language like the general purpose F Sharp programming language (F#) but closer to Elm and F# than to H for Haskell and especially P for Purescript. Also, the name "fig-lang" was already used for an organization name on GitHub...
The language will offer some extensions to the Elm language that are commonly considered to be deficiencies in the current Elm implementation, but in general this will be back compatible with current Elm source code so that current Elm code can be compiled by the Ficus compiler although it isn't guaranteed that the extended Ficus source code can be compiled by the current Elm compiler. Soome such extensions that are considered, from quite simple to quite complex, are as follows:
- Numeric integer literals and the mantissas of floating point numbers will be able to have embedded underscore
_characters that can be used as visual separators to make long numbers easier to read, such as using these to separate every three digits. - The built-in
ListType can be specified by just enclosing the name of any Type in square brackets (rather than requiringList <Type>and theListType will be exported from the core "List" module by fact rather than by the current assumption to make this type accessible even when a defined sub-module redefines the meaning ofList(the current Type definition can then be referenced by the qualifiedList.Listin spite of the redefinition). - Various bugs and deficiencies that won't affect current Elm source code can be fixed such as allowing the Pattern target of
case ... ofexpressions to be negative integers. - There will be a full stack of numeric Type's as to signedness and bittedness such as signed and unsigned versions of (at least) 8, 16, 32, and 64 bit integers as well as (at least) 32 and 64 bit floating point numbers; these will not conflict with current Elm's
IntandFloatas these will default to the current use asInt32andFloat64except when in JavaScript compatibility mode (current Elm mode) whereIntwill actually be implemented asFloat. - A built-in implementation of linearly indexed arrays called the
Array aType which will replace the current coreArray aType except when running in full Elm compatibility mode; in other than compatibility mode, the old core tree-basedArray atype will be available through a qualified reference (Array.Array a). - Scoped Type Variables where Type signatures including Type variables will be defined to be the same as any Type variable of the same name in any enclosing scope; this should prevent many of the Type Inference engine failures with the current Elm compiler implementation which doesn't do this.
- Existential Type Variables which is a form of "forall" for Type variables in Type signatures so they do not have to be mentioned on the left side of a Type signature, and further which are defined as a unique Type upon instantiation as a real Type that has the same properties as the instantiated Type but are not considered the same Type: this prevents certain types of Type unsafety when these Type's are used for functional composition chains or combinators in that one will then not be able to intermix such chains.
- Higher Kinded Type's (HKT's), which mean that an instantiatable real Type is defined only when actual values of its Type variables are applied: Examples are one doesn't have a
List Intfrom aList auntilIntis "applied" toList; one doesn't have aTask e auntil real Types are applied for the error Typeeand the result Typea; HKT's are needed in order to be able to define such types more generally as required for general TypeAbility's as in the following feature, although probably only Kind's of rank two above the current rank one are actually needed and use of these types may be limited to only the following Typeability's and their associated interface functions in order to prevent some types of Type ambiguity. - Type
Ability's, equivalent to Haskell and PureScript Type Classes, which mean that the programmer can define and use Type interface functions that can only be applied when they are defined for a given Type. For instance, using HKT's, amapfunction can only be applied to aList aType when there is an implementation (default or explicit) of themapfunction as it can be used within the rules for mapping for theList aType so thatmaphas aabilitydefined Type Annotation ofmap : (Mappable m) +> (a -> b) -> m a -> m bwhich when theMappableabilityis defined for theListType becomesmap : (a -> b) -> List a -> List bfor thisListType.
This is an implementation of the "ficus-lang" compiler whose file name will be "fcs" (or fcs.exe on Windows) and with native source file extensions to be ".fcs", with configuration file named "ficus.json"; it will also be combatible with the Elm language ".elm" source files and the Elm language configuration files "elm.json", which if both are used as per the usual Elm compiler use, will compile to JavaScript and/or HTML files or Web Assembly versions of these that will produce the same output as if the Elm compiler were used directly (backward compatible) although not exactly the same. However, this does not imply that source files with the ".fcs" extension or compilations using the "ficus.json" configuration will be usable by the Elm compiler even if their names are changed to be in line with the requirements of the Elm compiler. The compiler will accumulate Packages by tagged version number in a Package Cache named and located as suits the operating system on which the compiler is installed such as "$HOME/.ficus/packages/..." for Linux-like OS's with such Package Store's being compiled to their Type and Abstract Syntax Tree (AST) forms within a package "Artifacts.dat" file, which is an accumulation of the results of compilation of all of the exposed modules within the package, and some sort of documentation file for the package, which may be just a MarkDown format file or even converted to a PDF file. When compiling projects, intermediate results will be stored in a "ficus-stuff" folder inside the root folder for the project where the "ficus.json" file is located, and this "stuff" folder will contain a "i.dat" (interface's) file of an accumulation of the tree of all of the exposed Type interfaces for all used packages in the project, and a "o.dat" file (object's) of an accumulation of all the compiled AST's of all the used packages in the project; in addition there will be a "d.dat" file of the current hierarchy of the used packages of the project and for each project module and sub-module there will be ".fcsi" and ".fcso" files that will be the exposed interface's and AST's of each compiled module and sub-module, respectively. Along with the compiled AST's, the "o.dat" file will contain the "kernel" raw code for all used package modules that contain native code as obtained from their storage in each of the package "Artifacts.dat" files. In order to be able to generate code for statically typed languages such as Nim or C, the interface files will not only contain the exposed Type's (as Elm does) but also a full representation of all the inferred Type's used within each module that can be applied to the generated code output for statically-typed languages.
For initial development, the Ficus compiler will output Nim programming language source code that can be compiled into C code to be compiled to whatever target because Nim already has the features that C lacks of built-in parameterized Types (generics) and smart automatic reference counted memory management (it also has an optional cyclic reference breaker unneeded here as cyclic references are forbidden in Elm/Ficus); however, it is planned that Ficus will eventually output C code directly in order to be able to use the Tiny C Compiler (TCC) as a final C code compiler for fast debug development builds, as Nim cannot be used with TCC; TCC is over three times faster to compile than the clang compiler when using -O0 non-optimizing mode and the GCC compiler is almost twice as slow again in the same non-optimizing mode. Changing backend targets involves re-writing all of the "kernel" code generated by both the compiler and as used in the Elm standard packages of especially "elm/core" but also all of the "elm/..." packages such as "elm/random", "elm/html", "elm/browser", and so on, as well as the "elm-explorations/..." packages. In order to make it easy to import the new versions of these libraries, they will be imported by cloning them from this orgainization's adjacent repositories as "GitHub" links just as non-kernel packages can be imported from either the Elm Package database or directly from "GitHub" links. This allows a simple way of calling C/C++ code from the Ficus language as in just providing a compatible package that uses native C/C++ code internal to its implementation.
There is a possibility of supporting many/several "backend" code generators, each with its own code generation module that would be used depending on command line arguments made when compiling; however, in addition to the different Generate modules, there would also have to be made available different "kernel" code for those packages that have "kernel" modules, with each "kernel" module written in the target language code. This poses a slight bookkeeping problem in that currently all "kernel" code is embedded inside the compiled "objects" AST output. The easiest solution would seem to be to extract all "kernel" code in each target back-end language into separate output "object" compilation units, one for each language version of the "kernel" code. In this way, the Ficus compiler could easily support outputting to different languages such as JavaScript/TypeScript/Python/R programming languages, with the benefit that one would be writing code in the Ficus functional style and safety while still having access to the rich package ecosystems of these languages.
In this way the Ficus language will be more than a language for reliable web applications but "As delightfull as Elm, but a general purpose programming language".
To Be Added...
To Be Added...