Skip to content

Instantly share code, notes, and snippets.

@wavebeem
Last active December 2, 2015 00:10
Show Gist options
  • Save wavebeem/50755af9076bd1373d6b to your computer and use it in GitHub Desktop.
Save wavebeem/50755af9076bd1373d6b to your computer and use it in GitHub Desktop.
This Gist shows the current syntax of the Squiggle programming language, along with other ideas about how the syntax could look.
### Imports
let {JSON, document, console} = global
### Basic data
let namedConstants = [true, false, null, undefined]
let numbers = [1, 2, 1_000, 3.14, NaN, -Infinity]
let strings = ["hello,\n", "\u{20}", "\"world\"\u{2757}"]
let arrays = [[], [1, 2], [3, [[4]], [5]]]
let objects = [
{},
{a: "b"},
{key: 400, "first name": "Fatima"},
{("a" ++ "b"): "ab"}
]
### Trivial functions
let alwaysFourA = fn() 4
let incrementA = fn(x) x + 1
def alwaysFourB() = 4
def incrementB(x) = x + 1
def curriedAddThree(a) =
fn(b) fn(c) a + b + c
### First multi-line example
def addStringsAsNumbers(x, y) =
let x = Number(x)
let y = Number(y)
in x + y
### Named this example
def methodShowXLater(@this) =
setTimeout(fn() console.log(this.x), 300)
### Variadic function
def max(...xs) =
Math.max.apply(null, xs)
### Basic recursive function, obligatory factorial
def factorialA(n) =
if n < 0 then
error "cannot factorial of " ++ n.toString()
else if n == 0 or n == 1 then
1
else
n * factorialA(n - 1)
def factorialB(n) =
match n
case 0 => 1
case n => n * factorialB(n - 1)
### Working with a custom data type using just functions
def makePointA(x, y) = {x, y}
def pointAdd(a, b) =
let {x: ax, y: ay} = a
let {x: bx, y: by} = b
in makePointA(ax + bx, ay + by)
### Working with a custom data type using prototypes and methods
let pointProto = {
add: fn(@this, that)
makePointB(this.x + that.x, this.y + that.y),
scale: fn(@this, n)
let _ = console.log("DEBUG: scaling by", n)
in makePointB(this.x * n, this.y * n)
}
def makePointB(x, y) =
# This will be frozen and have the right prototype thanks to the `~` op
Object.create(pointProto) ~ {x, y}
### Working with updating objects
def updateNameA(person, name) =
if not person has "name" then
error "person didn't alreay have a name field"
else
person ~ {name}
def updateNameB(person, name) =
match person
case {name: _} =>
person ~ {name}
### Pattern match heavy algorithms
def sort(items) =
match items
case [] => []
case [x, ...xs] =>
let lt = xs.filter(fn(y, _, _) y < x)
let gt = xs.filter(fn(y, _, _) y >= x)
in sort(lt) ++ [x] ++ sort(gt)
def map(f, xs) =
match xs
case [] => []
case [x, ...xs] => [f(x)] ++ map(f, xs)
### Sneaky log stuff
def sneakyLogA(x) =
let _ = console.log(x)
in x
def tap(f, x) =
let _ = f(x)
in x
def sneakyLogB(x) =
tap(console::log, x)
### Lots of cases
def numberToEnglishA(n) =
if n == 1 then "one"
else if n == 2 then "two"
else if n == 3 then "three"
else if n == 4 then "four"
else "some other number"
def numberToEnglishB(n) =
match n
case 1 => "one"
case 2 => "two"
case 3 => "three"
case 4 => "four"
case _ => "some other number"
### Try example
def safeParse(text) =
match try JSON.parse(text)
case ["ok", obj] => obj
case ["fail", _] => {}
### Await example
def saveProfilePic(userId) =
await profile = httpGet("/user/" ++ userId) in
await image = httpGet(profile.imageUrl) in
await _ = writeFile(profile.userName ++ ".jpg", image.data) in
console.log("Saved image for " ++ profile.userName)
### Node.js HTTP server example
let http = require "http"
let port = 1337
let host = "127.0.0.1"
let url = "http://" ++ host ++ ":" ++ port.toString() ++ "/"
def handler(res, res) =
let headers = {"Content-Type": "text/plain"}
let _ = res.writeHead(200, headers)
let _ = res.end("Hello world\n")
in undefined
def start() =
http.createServer(handler).listen(port, host)
in console.log("Server running at " ++ url)
### Example app from http://mithril.js.org/
let Page = {
list: fn()
m.request({method: "GET", url: "pages.json"})
}
let Demo = {
controller: fn() {
pages: Page.list(),
rotate: fn()
pages().push(pages().shift())
},
view: fn(ctrl)
m("div", [
ctrl.pages().map(fn(page, _, _)
m("a", {href: page.url}, page.title)
),
m("button", {onclick: ctrl.rotate}, "Rotate links")
])
}
let _ = m.mount(document.getElementById("example"), Demo)
### Example Squiggle app using virtual-dom
let H = require "virtual-dom/h"
let diff = require "virtual-dom/diff"
let patch = require "virtual-dom/patch"
let createElement = require "virtual-dom/create-element"
let {Object, setInterval, document} = global
let {assign} = Object
def render(state) =
H("div", {className: "box"}, [state.count.toString()])
let app = Object()
def start() =
let _ = assign(app, {
state: {count: 0},
tree: render(app.state),
root: createElement(app.tree)
})
let _ = document.body.appendChild(app.root)
let _ = setInterval(update, 1000)
in undefined
def update() =
let state = app.state ~ {count: app.state.count + 1}
let tree = render(state)
let patches = diff(app.tree, tree)
let root = patch(app.root, patches)
in assign(app, {state, root, tree})
let _ = start()
### CSV parsing example
let papa = require "papaparse"
let fs = require "fs"
let {Object, console} = global
let csv = fs.readFileSync("data.tsv", "utf8")
let result = papa.parse(csv, {header: true})
let indexToName = [
"day",
"time",
"length",
"type",
"novdec"
]
def explode(x) =
x.trim().split(SOME_REGEX)
let counts = {
day: Object(),
time: Object(),
length: Object(),
type: Object(),
novdec: Object()
}
def inc(obj, key) =
let n =
if obj has key
then 1 + obj[key]
else 1
in assign(obj, {key: n})
result.data.forEach(fn(obj, _, _)
let fields = result.meta.fields
let n = fields.length
in fields.slice(1, n - 1).forEach(fn(k, i, _)
let name = indexToName[i]
let choices = explode(obj[k])
in choices.forEach(fn(choice)
inc(counts[name], choice)
)
)
)
in console.log(counts)
### END ###
### Imports
let {JSON, document, console} = global
### Basic data
let namedConstants = [true, false, null, undefined]
let numbers = [1, 2, 1_000, 3.14, NaN, -Infinity]
let strings = ["hello,\n", "\u{20}", "\"world\"\u{2757}"]
let arrays = [[], [1, 2], [3, [[4]], [5]]]
let objects = [
{},
{a: "b"},
{key: 400, "first name": "Fatima"},
{("a" ++ "b"): "ab"}
]
### Trivial functions
let alwaysFourA = func()
4
end
let incrementA = func(x)
x + 1
end
def alwaysFourB()
4
end
def incrementB(x)
x + 1
end
def curriedAddThree(a)
fn(b) fn(c) a + b + c
end
### First multi-line example
def addStringsAsNumbers(x, y)
let x = Number(x)
let y = Number(y)
x + y
end
### Named this example
def methodShowXLater(@this)
setTimeout(fn() console.log(this.x), 300)
end
### Variadic function
def max(...xs)
Math.max.apply(null, xs)
end
### Basic recursive function, obligatory factorial
def factorialA(n)
if n < 0 then
error "cannot factorial of " ++ n.toString()
else if n == 0 or n == 1 then
1
else
n * factorialA(n - 1)
end
end
def factorialB(n)
match n
case 0 then 1
case n then n * factorialB(n - 1)
end
end
### Working with a custom data type using just functions
def makePointA(x, y)
{x, y}
end
def pointAdd(a, b)
let {x: ax, y: ay} = a
let {x: bx, y: by} = b
makePointA(ax + bx, ay + by)
end
### Working with a custom data type using prototypes and methods
let pointProto = {
add: fn(@this, that) =
makePointB(this.x + that.x, this.y + that.y),
scale: fn(@this, n) do
console.log("DEBUG: scaling by", n)
makePointB(this.x * n, this.y * n)
end
}
def makePointB(x, y)
# This will be frozen and have the right prototype thanks to the `~` op
Object.create(pointProto) ~ {x, y}
end
### Working with updating objects
def updateNameA(person, name)
if not person has "name" then
error "person didn't alreay have a name field"
else
person ~ {name}
end
end
def updateNameB(person, name)
match person
case {name: _} then
person ~ {name}
end
end
### Pattern match heavy algorithms
def sort(items)
match items
case [] then []
case [x, ...xs] then
let lt = xs.filter(fn(y, _, _) y < x)
let gt = xs.filter(fn(y, _, _) y >= x)
sort(lt) ++ [x] ++ sort(gt)
end
end
def map(f, xs)
match xs
case [] then []
case [x, ...xs] then [f(x)] ++ map(f, xs)
end
end
### Sneaky log stuff
def sneakyLogA(x)
console.log(x)
x
end
def tap(f, x)
f(x)
x
end
def sneakyLogB(x)
tap(console::log, x)
end
### Lots of cases
def numberToEnglishA(n)
if n == 1 then "one"
else if n == 2 then "two"
else if n == 3 then "three"
else if n == 4 then "four"
else "some other number"
end
end
def numberToEnglishB(n)
match n
case 1 then "one"
case 2 then "two"
case 3 then "three"
case 4 then "four"
case _ then "some other number"
end
end
### Try example
def safeParse(text)
match try JSON.parse(text)
case ["ok", obj] then obj
case ["fail", _] then {}
end
end
### Await example
def saveProfilePic(userId)
await profile = httpGet("/user/" ++ userId)
await image = httpGet(profile.imageUrl)
await _ = writeFile(profile.userName ++ ".jpg", image.data)
console.log("Saved image for " ++ profile.userName)
end
### Node.js HTTP server example
let http = require "http"
let port = 1337
let host = "127.0.0.1"
let url = "http://" ++ host ++ ":" ++ port.toString() ++ "/"
def handler(res, res)
let headers = {"Content-Type": "text/plain"}
res.writeHead(200, headers)
res.end("Hello world\n")
end
def start()
http.createServer(handler).listen(port, host)
end
console.log("Server running at " ++ url)
### Example app from http://mithril.js.org/
let Page = {
list: func()
m.request({method: "GET", url: "pages.json"})
end
}
let Demo = {
controller: func()
{
pages: Page.list(),
rotate: func()
pages().push(pages().shift())
end
}
end,
view: func(ctrl)
m("div", [
ctrl.pages().map(fn(page, _, _)
m("a", {href: page.url}, page.title)
),
m("button", {onclick: ctrl.rotate}, "Rotate links")
])
end
}
m.mount(document.getElementById("example"), Demo)
### Example Squiggle app using virtual-dom
let H = require "virtual-dom/h"
let diff = require "virtual-dom/diff"
let patch = require "virtual-dom/patch"
let createElement = require "virtual-dom/create-element"
let {Object, setInterval, document} = global
let {assign} = Object
def render(state)
H("div", {className: "box"}, [state.count.toString()])
end
let app = Object()
def start()
assign(app, {
state: {count: 0},
tree: render(app.state),
root: createElement(app.tree)
})
document.body.appendChild(app.root)
setInterval(update, 1000)
end
def update()
let state = app.state ~ {count: app.state.count + 1}
let tree = render(state)
let patches = diff(app.tree, tree)
let root = patch(app.root, patches)
assign(app, {state, root, tree})
end
start()
### CSV parsing example
let papa = require "papaparse"
let fs = require "fs"
let {Object, console} = global
let csv = fs.readFileSync("data.tsv", "utf8")
let result = papa.parse(csv, {header: true})
let indexToName = [
"day",
"time",
"length",
"type",
"novdec"
]
def explode(x)
x.trim().split(SOME_REGEX)
end
let counts = {
day: Object(),
time: Object(),
length: Object(),
type: Object(),
novdec: Object()
}
def inc(obj, key)
let n =
if obj has key
then 1 + obj[key]
else 1
end
assign(obj, {key: n})
end
result.data.forEach(func(obj, _, _)
let fields = result.meta.fields
let n = fields.length
in fields.slice(1, n - 1).forEach(func(k, i, _)
let name = indexToName[i]
let choices = explode(obj[k])
in choices.forEach(func(choice)
inc(counts[name], choice)
end)
end)
end)
console.log(counts)
### END ###
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment