Skip to content

Instantly share code, notes, and snippets.

@rizo
Last active June 11, 2017 05:17
Show Gist options
  • Save rizo/8d8421e53d4dc9a8ca58 to your computer and use it in GitHub Desktop.
Save rizo/8d8421e53d4dc9a8ca58 to your computer and use it in GitHub Desktop.
Fold programming language examples.

Fold Programming Language

(This document is a draft.)

-- Single-line comments start with a doulbe dash.

---
In addition to the single-line comments there are block comments that start
with a triple dash and inline block comments delimited by `-- { ... }`.
---

-- Boolean operators are infix functions `and` and `or`.
-> true and true or false
 = true :: Bool

-- An integer value.
-> 42
 = 42 :: Int

--
-- Data Structures: Lists
--

-> [1, 2, 3, 4, 5]
 = [1, 2, 3, 4, 5] :: [Int]

-- Lists support range syntax.
-> [1 .. 5]
 = [1, 2, 3, 4, 5] :: [Int]

-> [1 .. 5]
 = [1, 2, 3, 4, 5] :: [Int]

-- Lists also support pattern matching.
-> [head, tail...] = [1 .. 5]
 = 1 :: Int
 = [2, 3, 4, 5] :: [Int]

--
-- Data Structures: Tuples
--

-- Tuples are heteogenic fixed-size data containers.
-> (1, 'a', "hello", [1 .. 10])
 = (1, 'a', "hello", [1 .. 10]) :: (int, char, string, [int])

-- Pattern matching is used for variable bindings.
-> a = (2.3, 'λ')
 = (2.3, 'λ') :: (float, char)

-> a, [head, rest...] = ("Свобода", [1, 2, 3, 4])
 = "Свобода" :: string
 = 1 :: Int
 = [2, 3, 4] :: [Int]


-- Type annotations can be used anywhere in the expressions.
-> ("Hello " :: string) + "World!"
 = "Hello World!" :: string

--
-- Data Structures: Records.
-- 

-- A record is just a tuple with labeled values.
-> a = {x = 2, y = 3}
 = {x = 2, y = 3} :: {x :: int, y :: int}

-- The previous record was an example of an anonymous record.
-- Although it was bound to a variable `a`, the record type was not 
-- previously declared.
-> type point = {x :: int, y :: int}
 = type {x :: int, y :: int}

-> p = {x = 2, y = 3}
 = {x = 2, y = 3} :: point

-- Record update syntax.
-> {p | x = 100, y = y + 50}

--
-- Functions
--

-- Function application.
-> sum 2 (1 + 1)
 = 4

-- Function application has precedence over operators.
-> sum 1 1 * 2    -- The precendence is as in `(sum 1 1) * 2`.
 = 4 :: int

-- Lambda functions.
-> \n -> n * n
 = λ :: Int -> Int

-> map
 = map :: (a -> b) -> [a] -> [b]

-> map (1 +) [1 .. 5]

-- Pattern matching lambda.
-> hello = \ None -> "Hello World" | Some name ->  "Hello " + name
 = hello :: String? -> String

-- String interpolation operator `%` with `{}` for formating.
-> function hello name lang
 ~   print % "{greeting lang}, {String.capitalize name}."
 ~     where greeting = case lang:
 ~     | "en" -> "Hello"
 ~     | "pt" -> "Olá"
 ~     | "ru" -> "Привет"
 ~     |  _   -> error "Unsuported language."
 ~ end
 = hello :: String -> String -> unit

-> alice, lang = "Maria Alice", "ru"
 = "Maria Alice" :: string
 = "ru" :: string

-- Regular positional application.
-> hello "Alice" "en"
 = () :: unit
"Hello, Alice."

-- Named keyword application.
-> hello name: "Alice" lang: "en"
 = () :: unit
"Hello, Alice."

-- The order of the keyword arguments does not have to be the same as in
-- the definition. The remaining positional arguments will be applied by
-- the provided order.
-> map (hello lang: "pt") ["João" "Maria" "André"]
 = ["Hello, João!" "Hello, Maria!" "Hello, André!"]

-- Named keyword application with scoped variable.
-> hello ~lang name: "Alice"
 = () :: unit

-- The previous application is equivalent to:
-> hello lang: lang name: "Alice"
 = () :: unit

-- Recursive factorial function implementation.
-> factorial = \ 0 -> 1
 >             | n -> n * factorial (n - 1)
 = factorial :: Int -> Int

-- Function composition and reverse application.
-> [1 .. 10] => filter even >> reverse >> take 3
 = [6 4 2]

-> iterate (+ "a") "" => take 5 >> tail >> filter (\s -> length s < 4)
 = ["a", "aa", "aaa"] :: string list

-- Operators are functions.

-> (+)
 = (+) :: {Number a} -> a -> a -> a

-> help (+)
 = (+) :: {Number a} -> a -> a -> a

   Produces a sum of two numerical values.
   The parameters of the sum function must implement the Number interface.

-> help help
 = help :: a -> a
  
   Help function.
   Acts as an identity function and prints expression docstring.


-- Sum all numbers in a list:
-> reduce (+) [1 .. 5]
 = 15 :: Int

-- Function definition.
-- Finds the maximum number in a list.
-> max list = reduce (\a b -> if (a > b) then: a else: b) list
 = max :: [Int] -> Int

-> max [2, 10, 3, 6, 9, 9]
 = 10

-- `for` macro.
-> for i <- [1 .. 3]:
 >     print ("Number: " + (i + 2)::String)
Number: 3
Number: 4
Number: 5

-> last list =
 >   case list:
 >     | [] -> None
 >     | [x] -> Some x
 >     | [x, rest...] -> last rest
 = last :: [a] -> a?


-- Some HTML

-> div class: "menu-container":
    ul id: "menu" class: "default-menu":
        map (li class: "menu-item") ["Home" "Products" "Contacts"]

-- `:` is a right associative function application operator, similar to Haskell's `$`.

--
-- Modules 
--

-> interface Comparable {a}
 >     type Ordering = LT | EQ | GT
 >     compare :: a -> a -> Ordering
 > end

-> module Comparable {int}
 >     compare x y =
 >         if | x == y -> EQ
 >            | x >  y -> GT
 >            | x <  y -> LT
 > end
 
 -- Function definition with docstring.

-> "Quick-sort sorting algorithm."
 > quicksort L (<) = match L:
 >  | [] => []
 >  | [x, xs...] => head + [x] + tail
 >      where head = quicksort (filter (\e -> e < x) xs) (<)
 >            tail = quicksort (filter (\e -> not (e < x)) xs) (<)
 = quicksort :: {Ord a} -> [a] -> (a -> a -> Ordering)


-- Print function definition.
 
-> print :: {Show a} -> [a] -> end: String -> sep: String -> Unit
-> print args... (end = "\n") (sep = " ") =
    IO.write ((String.join (map show args) with: sep) + end) to: IO.stdout

-> print "Hello" "World!" sep: ", "
Hello, World!


-- Function definition with meta-data.

{doc: "Produces a list of integers given the `start` and the `end`."
 added: 1.0, author: "Rizo Isrof"}
function range (from start = 0) (to stop) (by step = 1) -> [Int]
  if | start == stop -> []
     | else -> [start & (range (start + 1) stop step)]
end
:: range :: from: Int? -> to: Int -> by: Int? -> [Int]

-> range from: 10 to: 20 by: 5
:: [Int] = [10, 15, 20]


let rec filter pred =
  await >>= fun a ->
    if pred a then yield a >> lazy (filter pred)
    else filter pred

filter pred = do
  a <- await
  if | pred a -> yield a; filter pred
     | else   -> filter pred
end
  
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment