Scratch
SQL fragments for “More than Query” talk.
fun mask (guess, answer) =
let
fun mask2 (m, i, [], answer) = m
| mask2 (m, i, letter :: rest, answer) =
mask2 ((m * 3
+ (if sub(answer, i) = letter
then 2
else if isSubstring(str letter) answer
then 1
else 0)), i + 1, rest, answer)
in
mask2 (0, 0, explode guess, answer)
end;
fun maskToString m =
let
fun maskToString2 (m, s, 0) = s
| maskToString2 (m, s, k) =
maskToString2 (m div 3,
List.nth(["b", "y", "g"], m mod 3) ^ s,
k - 1)
in
maskToString2 (m, "", 5)
end;
val words = from w in file.wordle.words yield w.word;
fun maskCount (guess, remainingWords) =
from w in remainingWords
group m = mask (guess, w) compute c = count
compute count;
fun bestGuesses words =
from w in words,
maskCount = maskCount (w, words)
order maskCount desc;
fun remaining (words, []) = words
| remaining (words, (guess, m) :: rest) =
from w in (remaining (words, rest))
where maskToString (mask (guess, w)) = m;
Functional programming – values, types, operators
1 + 2;
> val it = 3 : int
"Hello, " ^ "world!";
> val it = "Hello, world!" : string
val integers = [1, 2, 3, 4, 5, 6, 7, 8];
> val integers = [1,2,3,4,5,6,7,8] : int list
fun filter f [] = []
| filter f (first :: rest) =
if (f first)
then first :: (filter f rest)
else filter f rest;
> val filter = fn : ('a -> bool) -> 'a list -> 'a list
filter (fn i => i mod 2 = 0) integers;
> val it = [2,4,6,8] : int list
val union = fn : 'a list * 'a list -> 'a list
val except = fn : 'a list * 'a list -> 'a list
val intersect = fn : 'a list * 'a list -> 'a list
val filter = fn : ('a -> bool) -> 'a list -> 'a list
val map = fn : ('a -> 'b) -> 'a list -> 'b list
val join = fn
: 'a list * 'b list * ('a * 'b -> bool)
-> ('a * 'b) list
from e in db.emps
where e.deptno = 10
yield {e.name, pay = e.sal + e.comm}
-- SQL
SELECT item, COUNT(*) AS c,
SUM(sales) AS total
FROM ProduceSales
WHERE item != 'bananas'
AND category IN ('fruit', 'nut')
GROUP BY item
ORDER BY item DESC;
item c total
====== ==== =====
apples 2 9
-- GoogleSQL pipe syntax
FROM ProduceSales
|> WHERE item != 'bananas'
AND category IN ('fruit', 'nut')
|> AGGREGATE COUNT(*) AS c, SUM(sales) AS total
GROUP BY item
|> ORDER BY item DESC;
from p in produceSales
where p.item != "bananas"
andalso p.category elem ["fruit", "nut"]
group p.item compute c = count,
total = sum of p.sales
order item desc
SELECT e.ename, e.sal
FROM emps AS e
WHERE e.deptno = 10
AND e.sal > (SELECT MAX(e2.sal)
FROM emps AS e2
WHERE e2.deptno = 20
AND e2.job = 'PROGRAMMER')
from e in scott.emps
where e.deptno = 10
andalso sal >
(from e2 in scott.emp
where e2.deptno = 20
andalso e2.job = "PROGRAMMER"
compute max 0 of e2.sal)
yield e.ename
from e in scott.emp
where e.deptno = 10
andalso
(forall e2 in scott.emp
where e2.deptno = 20
andalso e2.job = "PROGRAMMER"
require e.sal > e2.sal)
yield e.ename
datatype personnel_id =
EMPLOYEE of int
| CONTRACTOR of {ssid: string, agency: string};
type member = {name: string, deptno: int, id: personnel_id};
val members = [
{name = "Smith", deptno = 10, id = EMPLOYEE 100},
{name = "Jones", deptno = 20,
id = CONTRACTOR {ssid = "xxx-xx-xxxx", agency = "Cheap & cheerful"}];
val departments = scott.depts;
val primes = [2, 3, 5, 7, 11];
val bands = [["john", "paul", "george", "ringo"], ["simon", "garfunkel"]];
from i in [1, 2],
j in ["a", "b"],
k in [3, 4, 5, 6]
where i + k < 6;
> {i: int, j: string, k: int} list
from dept in [10, 30],
e in scott.emps
where e.deptno = dept
yield e.ename;
> string bag
from dept in [10, 30],
e in scott.emps
where e.deptno = dept
order e.sal desc
take 3
yield {e.deptno, e.ename};
> {deptno: int, ename: string} list
-- Delete employees who earn more than 1,000.
DELETE FROM scott.emps
WHERE sal > 1000;
-- Add one employee.
INSERT INTO scott.emps (empno, deptno, ename, job, sal)
VALUES (100, 20, 'HYDE', 'ANALYST', 1150);
-- Double the salary of all managers.
UPDATE scott.emps
SET sal = sal * 2
WHERE job = 'MANAGER';
-- Commit.
COMMIT;
(* Delete employees who earn more than 1,000. *)
delete e in scott.emps
where e.sal > 1000;
(* Add one employee. *)
insert scott.emps
[{empno = 100, deptno = 20, ename = "HYDE",
job = "ANALYST", sal = 1150}];
(* Double the salary of all managers. *)
update e in scott.emps
where e.job = "MANAGER"
assign (e, {e with sal = e.sal * 2});
(* Commit. *)
commit;
(* Delete employees who earn more than 1,000. *)
val emps2 =
from e in scott.emps
where not (e.sal > 1000);
(* Add one employee. *)
val emps3 = emps2 union
[{empno = 100, deptno = 20, ename = "HYDE", job = "ANALYST",
sal = 1150}];
(* Double the salary of all managers. *)
val emps4 =
from e in emps3
yield if e.job = "MANAGER"
then {e with sal = e.sal * 2}
else e;
(* Commit. *)
commit {scott with emps = emps4};
(* New and removed employees. *)
val empsAdded = emps4 except scott.emps;
val empsRemoved = scott.emps except emps4;
(* Compute the updated summary table. *)
val summary2 =
from s in scott.summary
union
(from e in empsAdded
yield {e.deptno, c = 1, sum_sal = e.sal}
union
(from e in empsRemoved
yield {e.deptno, c = ~1, sum_sal = ~sum_sal})
group s.deptno compute c = sum of c, sum_sal = sum of sum_sal
where c != 0);
(* Commit. *)
commit {scott with summary = summary2};
(* Morel "forwards" relation *)
(* Relation defined using algebra. *)
fun clerks () =
from e in emps
where e.job = "CLERK";
(* Query uses regular iteration. *)
from e in clerks,
d in depts
where d.deptno = e.deptno
andalso d.loc = "DALLAS"
yield e.name;
val it =
["SMITH", "ADAMS"] : string list;
(* Morel "backwards" relation *)
(* Relation defined using a predicate. *)
fun isClerk e =
e.job = "CLERK";
(* Query uses a mixture of constrained
and regular iteration. *)
from e,
d in depts
where isClerk(e)
andalso d.deptno = e.deptno
andalso d.loc = "DALLAS"
yield e.name;
val it =
["SMITH", "ADAMS"] : string list;
datatype 'a option = NONE | SOME of 'a;
SOME 1;
- from e in scott.emp
= where e.deptno = 10
= andalso (forall e2 in scott.emp
= where e2.job = "PROGRAMMER"
= require e.sal > e2.sal)
= yield {e.ename, e.sal};
val it =
[{ename="CLARK",sal=2450.0},{ename="KING",sal=5000.0},
{ename="MILLER",sal=1300.0}] : {ename:string, sal:real} list
(* Initial database value and type (schema). *)
val scott1 = db
: {emps: {name: string, empno: int, deptno: int,
hiredate: string} bag,
depts: {deptno: int, name: string} bag};
(* Shim that makes a v1 database look like v2. *)
fun scott2on1shim scott1 =
{emps =
fn () => from e in scott1.emps
yield {e with hiredate = Date.fromString(e.hiredate)},
depts = fn () => scott1.depts};
(* Shim that makes v3 database look like v1. *)
fun scott1on3shim scott3 =
{emps =
fn () => from e in scott3.emps
yield {e with hiredate = Date.toString(e.hiredate)
removing rating},
depts = fn () => scott3.depts};
(* An application writes its queries & views against version 2;
shims make it work on any actual version. *)
val scott = scott2;
fun recentHires () =
from e in scott.e
where e.hiredate > Date.subtract(Date.now(), 100);