Skip to content

Latest commit

 

History

History
481 lines (452 loc) · 29.6 KB

Cheatsheet.md

File metadata and controls

481 lines (452 loc) · 29.6 KB

Foi-vs-JS Cheatsheet

If you're familiar with JS and want to understand how to do something in Foi instead, the following is a lookup list of JS features/idioms and their (somewhat) equivalents in Foi:

JSFoiNotes
// line comment
/* block comment */
// line comment
/// block comment ///
Code Comment
var .. = let .. = const .. =def .. :Variable Definition
null undefinedemptyEmpty Value Literal
truefalsetrue falseBoolean Literal
123 3.14 -42123 3.14 -42Number Literal
0o127 0h3a6 0b10110\o127 \h3a6 \b10110Octal/Hex/Binary Literal
1_234_567.890_123\1_234_567.890_123Readable Number Literal
12345678901234567890n\@12345678901234567890Big Integer Literal
"hello" 'hello' `hello`"hello"String Literal
`string ${interpolation}`\`"string `interpolation`"Interpolated String Literal
{ x: 2 }< x: 2 >Object (Foi Record)
{ [propName]: 2 }< %propName: 2 >Computed Property Name
[ 2, 3 ]< 2, 3 >Array (Foi Tuple)
arr.includes(x)x ?in arrArray Includes
propName in objobj ?has propNameObject Property Exists
{ ...obj }< &obj >Object Spread (Foi Record Pick)
{ prop: obj.prop }< &obj.prop >Object Pick
[ ...arr ]< &arr >Array Spread (Foi Tuple Pick)
{ x }< :x >Concise Property
obj.prop obj[propName]obj.prop obj[propName]Object Property Access
arr[3]arr.3 arr[3]Array Index Access
arr.at(-1)arr.-1Relative Array Index Access
arr.slice(2,6)arr.[2..5]Array Range Access
new Map([[ obj, 42 ]])< %obj: 42 >Map (Foi Record)
new Set([ 1, 1, 2, 2 ])<[ 1, 1, 2, 2 ]>Set (Foi Tuple -- with duplicate filtering)
=:=Assignment
var { x } = ..
var [ x ] = ..
def < x >: ..Destructuring
!x!xBoolean Negate
!!x Boolean(x)?xBoolean Coerce
x && yx ?and yBoolean AND
x || yx ?or yBoolean OR
!(x && y)x !and yBoolean NOT AND (Foi NAND)
!(x || y)x !or yBoolean NOT OR (Foi NOR)
==?=Equality
!=!=Inequality
v == null?empty vIs null (Foi empty)
v != null!empty vIs Not null (Foi != empty)
x > yx ?> yGreater Than
!(x > y)x !> yNot Greater Than
x >= yx ?>= yGreater Than / Equal
!(x >= y)x !>= yNot Greater Than / Equal
x < yx ?< yLess Than
!(x < y)x !< yNot Less Than
x <= yx ?<= yLess Than / Equal
!(x <= y)x !<= yNot Less Than / Equal
y > x && y < z(?<>)(x,y,z)In Between, Not Inclusive
y >= x && y <= z(?<=>)(x,y,zIn Between, Inclusive
y < x || y > z(!<>)(x,y,z)Not In Between, Not Inclusive
y <= x || y >= z(!<=>)(x,y,z)Not In Between, Inclusive
++Plus/Concatenation
--Minus
**Multiply
//Divide
import .. from ..
import { .. } from ..
def .. : import from ..
def < .. >: import from ..
Module Import
export ..
export { .. }
export { .. }Module Export
function =>defnFunction Definition
return => ..^Function Return
function myFunc(x = 0) ..defn myFunc(x: 0) ..Function Parameter Default
function myFunc(...params) ..defn myFunc(*params) ..Function Rest Parameter
myFunc = x => y => x * ydefn myFunc(x) ^defn(y) ^x * y(Strict) Curried Function Declaration
myFunc(1,2,3)myFunc(1,2,3)Function Call
myFunc(...args)myFunc(...args)Function Call Argument Spread
myFunc({ x: 1, y: 2 })myFunc(x:1, y:2)"Named Arguments" (at call-site) Idiom
x > 0 ? y : z if (x > 0) y else z
switch (true) case (x > 0): y; break; default: z
?{ ?[x ?> 0]: y; ?: z }
?(x){ ?[?> 0]: y; ?: z }
Decision Making (Foi Pattern Matching)
if (x > 0) myFunc(x)?[x ?> 0]: myFunc(x)Statement Guard Clause
for (..) while (..) do .. while (..)~eachImperative Loop
.map(..)~mapMap (Foi Comprehension)
.flatMap(..)~flatMap ~bind ~chain ~<Flat-Map (Foi Comprehension)
.filter(..)~filterFilter (Foi Comprehension)
.reduce(..) .reduceRight(..)~fold ~foldRReduce (Foi Fold)
[...new Array(4)].map((v,i)=>i)0..3Integer Range List: 0,1,2,3
(async function(){ var x = await y; .. })()Promise ~<< (x:: y) { .. }Async..Await (Foi Promise Do Comprehension)
Promise.resolve(42)Promise@42Resolved Promise
new Promise(res => { .. })Promise(defn(res){ .. })Promise Constructor
const subj = {}; subj.pr = new Promise(res => { subj.resolve = res; })def subj: PromiseSubject@;Promise Subject
function* async function*Gen@ ..Generator
for (let x of it) { .. }
for await (let x of it) { .. }
it ~<* (x) { .. }Iterator/Async Iterator Consumption (Foi Promise Do Loop Comprehension)
Observable StreamPushStream PullStreamLazy/Concurrent Data
42 |> myFunc(#) |> anotherFunc(#,2)42 #> myFunc #> anotherFunc(#,2)Pipeline (proposed for JS)
var x: int = 42def x: 42 :as intTypeScript Static Annotation (Foi Value-Type Annotation)
type MyType = ..deft MyType ..Custom Type Definition
--------------------------------------------------------
NaN Infinity -Infinity(not in Foi)
new super class .. extends static this instanceof(not in Foi)
delete void typeof yield(not in Foi)
try .. catch(not in Foi)
x === y x++ ++x x-- --x x += y x -= y x *= y x /= y x %= y x &= y x |= y x **= y x &&= y x ||= y x ??= y x <<= y x >>= y x >>>= y x ** y x << y x >> y x >>> y ~x x % y x & y x | y x ^ y x?.y x?.[y] x?.(y) x ?? y(not in Foi)
--------------------------------------------------------
(not in JS)(*)(2,3,4)N-Ary Operator (as function) Invocation
(proposed for JS)myFn|1| myFn|1,,3|Function Partial Application
(not in JS)myFn'(3,2,1)Function Reverse Application
(not in JS)arr.<0,2,3> obj.<first,last,email>Record/Tuple Subset Selection
(not in JS)2..5 "a".."f"Range Of Sequential Values
(not in JS):over (..)Closure Side Effect Declaration
(not in JS)defn myFunc() ?[ .. ]: ..Function Precondition
(not in JS)Promise ~<* { .. }Promise Looping
(not in JS)def myFunc: incVal +> doubleVal +> formatNum
def myFunc: formatNum <+ doubleVal <+ incVal
Function Composition
(not in JS)defn myFunc(v) #> incVal #> doubleVal #> formatNumPipeline Function
(not in JS)(#>)(42,...fns)Dynamic Pipeline
(not in JS)defn add(x)(y) ^x + y(Loose) Curried Function Declaration
(not in JS)Id Value Number None Maybe Either Left Right List IO Gen PushStream PullStream Channel (CSP) ~ap ~foldMap ~cata ~<<Monads, Monadic Comprehensions

Comparison Examples

Here are some screenshots showing typical JS code (on top or left, in each image) to the equivalent Foi code (on bottom or right, in each image).

Comparison: chunking an array Comparison: async..await fetch + rendering html

Comparison: memoized fibonacci number computation
Comparison: converting string of binary digits into base-10 number
Comparison: iterative BFS algorithm, finding size of largest region in matrix

The syntax highlighting of the Foi code in these screenshots is produced by the Foi-Toy tool included in this repository.

You can find some more examples of Foi code here.

Syntax Weight/Density

Foi more strongly favors the usage of symbolic operators over generic keywords (e.g. Foi ^ vs JS return). Symbol re-use in compound (multi-character) operators is also prioritized for creating a visual symmetry between related features (e.g., the common ? in boolean operators like ?>, ?<, and ?=). And Foi uses symbol visual semantics to signal behavior (e.g. +> pointing in left-to-right direction to indicate the flow of data). Lastly, Foi makes some choices in its operators (especially compound operators) that are unique/rare compared to other languages (e.g., ~<*), and will thus be less familiar at first glance.

As such, Foi code may indeed appear to be more heavy/dense in its syntax when you first start reading it.

While it's important to admit the intentionality in these design decisions, it's also important to keep a full context for such analysis and opinion forming.

The following table is a comprehensive list of all non-alphanumeric symbols in JS, as well as in Foi, presented respectively in side-by-side columns. In many cases, the row pairings in this table attempt to match like features, but there are many JS or Foi features that are distinct and don't match up; those "random" row pairings are only to slot things into a table for counting purposes.

As a summary of the symbol counts below:

  • JS has 79 distinct symbol sequences (single-character, or compound multi-character); there are another 12 proposed JS symbols (Stage 2 or 3 proposals, somewhat likely to happen).

    • 28 of them are single-character (plus 1 proposed)
    • 30 of them are double-character (plus 2 proposed)
    • 12 of them are triple-character (plus 3 proposed)
    • 9 of them are four+ characters (plus 6 proposed)
    • 182 total characters (plus 71 proposed characters)
    • Regular expression literals can't be length-analyzed
  • Foi has 88 distinct symbol sequences.

    • 26 of them are single-character
    • 21 of them are double-character
    • 21 of them are triple-character
    • 20 of them are four+ characters
    • 260 total characters

As you can see, JS has 79 distinct symbols (91 including likely-to-land future proposals), whereas Foi has 88 distinct symbols. Overall character count of all symbols is 253 in JS (proposals included) versus 260 for Foi.

So, is Foi more syntactically heavy/verbose than JS? Perhaps a little bit, yes. But probably not significantly moreso, no.

Of course, these symbol/character counts don't tell the whole story. It's also important to understand the usage frequency of each type and length of symbol/operator. Moreover, the "symbol density" of a code base depends on how many of these symbols would appear near/adjacent to each other, with other intervening alphanumeric characters "spreading" them out or not.

Both of these factors are highly dependent on the code base/style, so can't be objectively compared in a universal sense.

JS Symbol/OperatorDescription Foi Symbol/OperatorDescription
@Decorator (proposed) @Monad Constructor
#Private Member #Pipeline Topic
_Identifier Character _Identifier Character
$Identifier Character $+Set Append
,Comma ,Comma
.Property Access .Property Access
;Statement End Semicolon ;Statement End Semicolon
:Property Definition :Initial Assignment, Property Definition
`Template String Delimiter `Interpolated String Delimiter, Interpolated Expression Delimiter
"String Delimiter "String Delimiter
'String Delimiter 'Function Call Argument Reversal
\Escape \Escape
~Bitwise Negate (1's complement) \@Large Number Escape (monadic)
!! !Boolean Cast / Negate ? !Boolean Cast / Negate
% %=Remainder / Assignment %Computed Property Name
^ ^=Bitwise Negate / Assignment ^Return (function value)
& &=Bitwise And / Assignment &Pick (record/tuple value)
+ +=Addition / Assignment +Addition
- -=Subtraction / Assignment -Subtraction
* *=Multiplication / Assignment *Multiplication
/ /=Divide / Assignment /Divide
* *=Multiplication / Assignment *Multiplication
( )Expression Grouping, Function Call Arguments ( )Expression Grouping, Function Call Arguments
[ ]Array Literals, Property Access [ ]Property Access
{ }Object Literals, Blocks { }Blocks
| |=Bitwise Or / Assignment | |Function Call Partial Application
#{ } #[ ]Record / Tuple (proposed) < >Record, Tuple
** **=Exponentiation / Assignment <[ ]>Set
=(Re-)Assignment :=Re-Assignment
== !=Equality / Inequality ?= !=Equality / Inequality
=== !==Strict Equality / Inequality ?$= !$=Set Equality / Inequality
< !(x < y)Less Than / Not Less Than ?< !<Less Than / Not Less Than
<= !(x <= y)Less Than Or Equal / Not Less Than Or Equal ?<= !<=Less Than Or Equal / Not Less Than Or Equal
> !(x > y)Greater Than / Not Greater Than ?> !>Greater Than / Not Greater Than
>= !(x >= y)Greater Than Or Equal / Not Greater Than Or Equal ?>= !>=Greater Than Or Equal / Not Greater Than Or Equal
=>Arrow Function ?<=> !<=>Between (inclusive) / Not Between
&& &&=Boolean And / Assignment ?<> !<>Between (non-inclusive) / Not Between
|| ||=Boolean Or / Assignment ..Range / Slice
// /* */Line Comment / Multiline Comment // ///Line Comment / Multiline Comment
...Spread / Rest ...Spread / Gather
\uUnicode Escape \uUnicode Escape
0o 0OOctal Number Prefix \oOctal Number Prefix
0b 0BBinary Number Prefix \bBinary Number Prefix
0x 0XHexadecimal Number Prefix \hHexadecimal Number Prefix
|>Pipeline (proposed) #>Pipeline
%%Pipeline Topic Marker (proposed) ::Do-Style Chain Assignment
?Ternary Conditional ?{ }Pattern Match Expression (Independent)
?. ?.[ ?.(Optional Property Access ?( ){ }Pattern Match Expression (Dependent)
?? ??=Nullish-Coalescing / Assignment ?[ ]Guard Clause, Pattern Match Conditional, Function Precondition
>> >>=Bitwise Shift Right / Assignment ~<Chain/Bind/FlatMap Comprehension (Terse)
>>> >>>=Bitwise Shift Right (Zero Padded) / Assignment ~<*Looping Do-Syntax (monadic)
<< <<=Bitwise Shift Left / Assignment ~<<Do-Syntax (monadic)
++(Pre, Post) Increment +>Compose (left-to-right)
--(Pre, Post) Decrement <+Compose (right-to-left)
function* yield* import.meta new.target
(proposed) !in !instanceof function.sent await.all await.race await.allSettled await.any
Keyword+Symbol (hybrid) ~each ~map ~filter ~fold ~foldMap ~foldR ~chain ~bind ~flatMap ~ap ~cata :as :over ?empty !empty ?and !and ?or !or ?as !as ?in !in ?has !hasKeyword+Symbol (hybrid)
${ }Interpolated Expression Delimiter
/p*[^a](?<tt>er){1,3}n/Regular Expression Literals

The question that matters the most is: "Does Foi allow me to express and understand programs better?" And you'll only be able to judge that properly once you learn and practice with it, so don't rush to judgement at first glance!

Further Details

Now check out the Foi Guide for a detailed exploration of the language.

For implementers or language design enthusiasts, a formal grammar specification is in progress.

License

License

All code and documentation are (c) 2022-2023 Kyle Simpson and released under the MIT License. A copy of the MIT License is also included.