Icicle has a small syntax, designed to look like simple functional languages. It’s whitespace sensitive (a bit like python) and is designed to be concise and clear.
-- single line comments start with two dashes
{- multiline comments are done like this
{- and can be nested -}
-}
True -- It's true, comments can come after expressions
1 + {- and in the middle of them -} 2Icicle support a wide range of literals, including dates.
() : Unit
True : Bool
False : Bool
1 : Num a => a -- Can be either an Int or Double
1.4 : Double
"one" : String
2020-01-01 : TimeSome simple sum types are baked in (while others can be created by users).
Some "work" : Option String
None : Option a
Left "hi" : Sum String b
Right "ok" : Sum c StringApplying functions has a very minimal syntax, just whitespace is used to separate a function from their arguments.
-- apply the sum function to the argument amount
sum amountTo apply to multiple arguments, just use another space
-- max_by takes two arguments
max_by total_sales storeThe simplest conditional is an if expression
if value > 10 then
Some value
else
NoneYou can also pattern match on expressions
case total of
Some value then
value
None then
0Let expressions provide a simple context under which a new name is available.
let
total =
sum value
number =
count value
in
total / numberOne doesn’t usually need to put semi-colons between expressions in a let statement, just line them up vertically. But, if it’s nicer to put them on a single line one can explicitly separate them
let a = 2; b = 3 in a + bLet expressions are the simplest contexts, but others are critical too, including filters, folds, windows, and group bys.
Users can trivially write helper functions and custom folds to make writing queries easier.
mean a = sum a / count aThe arguments which must be provided to mean here are specified before the equals sign (i.e., a), and are available in the body of the function.
Type signatures are never required when writing features, but can be used to document and check functions. Type signatures come after a single colon.
three : Int
three = 3Function types include arrows between their arguments to their result.
add : Int -> Int -> Int
add a b = a + bTypes which start with a capital letter are fixed types, while those with a lower case letter are polymorphic types, meaning the caller of the function can decide what type to use.
identity : a -> a
identity a = aThe function identity simply returns the value passed to it, and can be passed a value of any type.
Some types may also contain constraints on the types which can inhabit them
four : Num a => a
four = 4The above can be read as
for all types ‘a’, given that ‘a’ is a number; four is a value of type ‘a’
Streams of data are required to have their type defined. Any type of data is available, including complex records. When a record is used as an input, the fields of the record are bound to names automatically.
input age : IntQueries start with their name, and the data source which will be queried
feature total_sales =
from sales
in sum amountModules are used to separate files and allow collaboration. Modules can contain imports (which must come first), input declarations, function definitions, type definitions, and features.
module Age where
import Helpers
type Adult
= Adult ()
| Child ()
input age : Int
adult : Int -> Adult
adult i =
if i >= 18 then
Adult ()
else
Child ()
feature is_adult =
from age
in adult (newest value)