diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 45dc4fa01..20919689e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -37,6 +37,10 @@ jobs: output: ctfp-reader-ocaml.pdf - input: ctfp-print-ocaml.tex output: ctfp-print-ocaml.pdf + - input: ctfp-reader-reason.tex + output: ctfp-reader-reason.pdf + - input: ctfp-print-reason.tex + output: ctfp-print-reason.pdf steps: - name: Set up Git repository @@ -97,6 +101,10 @@ jobs: destination: category-theory-for-programmers--print--ocaml-- - source: ctfp-reader-ocaml.pdf destination: category-theory-for-programmers--reader--ocaml-- + - source: ctfp-print-reason.pdf + destination: category-theory-for-programmers--print--reason-- + - source: ctfp-reader-reason.pdf + destination: category-theory-for-programmers--reader--reason-- steps: - name: Download build assets (${{ matrix.assets.source }}) uses: actions/download-artifact@v2 diff --git a/src/Makefile b/src/Makefile index 3c6c2da4a..22eb48ba4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ # Igal Tabachnik, 2007. # Based on work by Andres Raba et al., 2013-2015. -.PHONY: default all clean out-dir version.tex scala ocaml +.PHONY: default all clean out-dir version.tex scala ocaml reason DIR := $(shell pwd) GIT_VER := $(shell git describe --tags --always --long | tr -d '\n') @@ -16,8 +16,10 @@ SCALATEXFILES = ctfp-reader-scala.tex ctfp-print-scala.tex # todo make this a ma OCAMLTEXFILES = ctfp-reader-ocaml.tex ctfp-print-ocaml.tex # todo make this a macro +REASONTEXFILES = ctfp-reader-reason.tex ctfp-print-reason.tex # todo make this a macro + # Top-level LaTeX files from which CTFP book can be generated -TOPTEXFILES = version.tex $(DEFAULTTOPTEX) $(SCALATEXFILES) $(OCAMLTEXFILES) +TOPTEXFILES = version.tex $(DEFAULTTOPTEX) $(SCALATEXFILES) $(OCAMLTEXFILES) $(REASONTEXFILES) # Default PDF file to make DEFAULTPDF:=$(DEFAULTTOPTEX:.tex=.pdf) @@ -28,6 +30,9 @@ SCALAPDF:=$(SCALATEXFILES:.tex=.pdf) # OCaml PDF file to make OCAMLPDF:=$(OCAMLTEXFILES:.tex=.pdf) +# ReasonML PDF file to make +REASONPDF:=$(REASONTEXFILES:.tex=.pdf) + # Other PDF files for the CTFP book TOPPDFFILES:=$(TOPTEXFILES:.tex=.pdf) @@ -37,7 +42,7 @@ OPTFILES = opt-print-ustrade.tex \ opt-scala.tex # All the LaTeX files for the CTFP book in order of dependency -TEXFILES = $(TOPTEXFILES) $(SCALATEXFILES) $(OCAMLTEXFILES) $(OPTFILES) +TEXFILES = $(TOPTEXFILES) $(SCALATEXFILES) $(OCAMLTEXFILES) $(REASONTEXFILES) $(OPTFILES) default: suffix='' default: out-dir $(DEFAULTPDF) # todo cover @@ -50,6 +55,9 @@ scala: clean out-dir version.tex $(SCALAPDF) ocaml: suffix='-ocaml' ocaml: clean out-dir version.tex $(OCAMLPDF) +reason: suffix='-reason' +reason: clean out-dir version.tex $(REASONPDF) + # Main targets $(TOPPDFFILES) : %.pdf : %.tex $(TEXFILES) if which latexmk > /dev/null 2>&1 ;\ diff --git a/src/content/1.1/code/reason/snippet01.re b/src/content/1.1/code/reason/snippet01.re new file mode 100644 index 000000000..f497fd514 --- /dev/null +++ b/src/content/1.1/code/reason/snippet01.re @@ -0,0 +1,6 @@ +module type Polymorphic_Function_F = { + type a; + type b; + + let f: a => b; +}; diff --git a/src/content/1.1/code/reason/snippet02.re b/src/content/1.1/code/reason/snippet02.re new file mode 100644 index 000000000..f97d334f2 --- /dev/null +++ b/src/content/1.1/code/reason/snippet02.re @@ -0,0 +1,6 @@ +module type Polymorphic_Function_G = { + type b; + type c; + + let g: b => c; +}; diff --git a/src/content/1.1/code/reason/snippet03.re b/src/content/1.1/code/reason/snippet03.re new file mode 100644 index 000000000..cc558d053 --- /dev/null +++ b/src/content/1.1/code/reason/snippet03.re @@ -0,0 +1,10 @@ +module Compose_Example = + ( + F: Polymorphic_Function_F, + G: Polymorphic_Function_G with type b = F.b, + ) => { + /** ReasonML doesn't have a compose operator. So, creating one. **/ + let (>>) = (g, f, x) => g(f(x)); + + let compose: 'a => 'c = (G.g >> F.f: 'a => 'c); +}; diff --git a/src/content/1.1/code/reason/snippet04.re b/src/content/1.1/code/reason/snippet04.re new file mode 100644 index 000000000..19858bcb0 --- /dev/null +++ b/src/content/1.1/code/reason/snippet04.re @@ -0,0 +1,19 @@ +module Compose_Three_GF = + ( + F: Polymorphic_Function_F, + G: Polymorphic_Function_G with type b = F.b, + H: Polymorphic_Function_H with type c = G.c, + ) => { + let compose: 'a => 'd = H.h >> (G.g >> F.f); +}; + +module Compose_Three_HG = + ( + F: Polymorphic_Function_F, + G: Polymorphic_Function_G with type b = F.b, + H: Polymorphic_Function_H with type c = G.c, + ) => { + let compose: 'a => 'd = H.h >> G.g >> F.f; +}; + +Compose_Three_GF.compose == Compose_Three_HG.compose \ No newline at end of file diff --git a/src/content/1.1/code/reason/snippet05.re b/src/content/1.1/code/reason/snippet05.re new file mode 100644 index 000000000..0dab30dc4 --- /dev/null +++ b/src/content/1.1/code/reason/snippet05.re @@ -0,0 +1 @@ +let id = x => x; diff --git a/src/content/1.1/code/reason/snippet06.re b/src/content/1.1/code/reason/snippet06.re new file mode 100644 index 000000000..ce66bc615 --- /dev/null +++ b/src/content/1.1/code/reason/snippet06.re @@ -0,0 +1,2 @@ +f >> id; +id >> f; diff --git a/src/content/1.10/code/reason/snippet01.re b/src/content/1.10/code/reason/snippet01.re new file mode 100644 index 000000000..82fd71263 --- /dev/null +++ b/src/content/1.10/code/reason/snippet01.re @@ -0,0 +1 @@ +let alpha: 'a . f('a) => g('a); \ No newline at end of file diff --git a/src/content/1.10/code/reason/snippet02.re b/src/content/1.10/code/reason/snippet02.re new file mode 100644 index 000000000..37793c3bb --- /dev/null +++ b/src/content/1.10/code/reason/snippet02.re @@ -0,0 +1 @@ +let alpha: f('a) => g('a); diff --git a/src/content/1.10/code/reason/snippet03.re b/src/content/1.10/code/reason/snippet03.re new file mode 100644 index 000000000..37793c3bb --- /dev/null +++ b/src/content/1.10/code/reason/snippet03.re @@ -0,0 +1 @@ +let alpha: f('a) => g('a); diff --git a/src/content/1.10/code/reason/snippet04.re b/src/content/1.10/code/reason/snippet04.re new file mode 100644 index 000000000..e100551fb --- /dev/null +++ b/src/content/1.10/code/reason/snippet04.re @@ -0,0 +1,4 @@ +let safe_head = + fun + | [] => None + | [x, ...xs] => Some(x); diff --git a/src/content/1.10/code/reason/snippet05.re b/src/content/1.10/code/reason/snippet05.re new file mode 100644 index 000000000..676ddeec5 --- /dev/null +++ b/src/content/1.10/code/reason/snippet05.re @@ -0,0 +1 @@ +compose(fmap(f), safe_head) == compose(safe_head, fmap(f)); diff --git a/src/content/1.10/code/reason/snippet06.re b/src/content/1.10/code/reason/snippet06.re new file mode 100644 index 000000000..10aa5ee09 --- /dev/null +++ b/src/content/1.10/code/reason/snippet06.re @@ -0,0 +1,2 @@ +/* Starting with empty list */ +let fmap = (f, safe_head([])) == fmap(f, None) == None; \ No newline at end of file diff --git a/src/content/1.10/code/reason/snippet07.re b/src/content/1.10/code/reason/snippet07.re new file mode 100644 index 000000000..2580b2a24 --- /dev/null +++ b/src/content/1.10/code/reason/snippet07.re @@ -0,0 +1 @@ +let safe_head = (fmap, f, []) == safe_head([]) == None; \ No newline at end of file diff --git a/src/content/1.10/code/reason/snippet08.re b/src/content/1.10/code/reason/snippet08.re new file mode 100644 index 000000000..ce746666e --- /dev/null +++ b/src/content/1.10/code/reason/snippet08.re @@ -0,0 +1 @@ +let fmap = (f, safe_head([x, ... xs])) == fmap(f(Some(x))) == Some(f(x)); \ No newline at end of file diff --git a/src/content/1.10/code/reason/snippet09.re b/src/content/1.10/code/reason/snippet09.re new file mode 100644 index 000000000..348cc6299 --- /dev/null +++ b/src/content/1.10/code/reason/snippet09.re @@ -0,0 +1,2 @@ +let safe_head = + (fmap([x, ...xs])) == safe_head(f([x, ... xs])) == Some(f(x)); \ No newline at end of file diff --git a/src/content/1.10/code/reason/snippet10.re b/src/content/1.10/code/reason/snippet10.re new file mode 100644 index 000000000..82c9c23c9 --- /dev/null +++ b/src/content/1.10/code/reason/snippet10.re @@ -0,0 +1,4 @@ +let rec fmap = f => + fun + | [] => [] + | [x, ...xs] => [f(x), ...fmap(f, xs)]; diff --git a/src/content/1.10/code/reason/snippet11.re b/src/content/1.10/code/reason/snippet11.re new file mode 100644 index 000000000..0a16ee5e6 --- /dev/null +++ b/src/content/1.10/code/reason/snippet11.re @@ -0,0 +1,4 @@ +let rec fmap = f => + fun + | None => None + | Some(x) => Some(f(x)); diff --git a/src/content/1.10/code/reason/snippet12.re b/src/content/1.10/code/reason/snippet12.re new file mode 100644 index 000000000..2afb461ae --- /dev/null +++ b/src/content/1.10/code/reason/snippet12.re @@ -0,0 +1,11 @@ +/* ReasonML requires mutually recursive functions +* to be defined together */ +let rec length: list('a) => const(int, 'a) = ( + fun + | [] => Const(0) + | [_, ...xs] => Const(1 + un_const(length(xs))): + list('a) => const(int, 'a) +) +and un_const: 'c 'a. const('c, 'a) => 'c = + fun + | Const(c) => c; diff --git a/src/content/1.10/code/reason/snippet13.re b/src/content/1.10/code/reason/snippet13.re new file mode 100644 index 000000000..39d116740 --- /dev/null +++ b/src/content/1.10/code/reason/snippet13.re @@ -0,0 +1,3 @@ +let un_const: 'c 'a. const('c, 'a) => 'c = + fun + | Const(c) => c; diff --git a/src/content/1.10/code/reason/snippet14.re b/src/content/1.10/code/reason/snippet14.re new file mode 100644 index 000000000..9f9483ead --- /dev/null +++ b/src/content/1.10/code/reason/snippet14.re @@ -0,0 +1 @@ +let length: list('a) => int; diff --git a/src/content/1.10/code/reason/snippet15.re b/src/content/1.10/code/reason/snippet15.re new file mode 100644 index 000000000..e1c2efa3e --- /dev/null +++ b/src/content/1.10/code/reason/snippet15.re @@ -0,0 +1,3 @@ +let scam: 'a. const('int, 'a) => option('a) = + fun + | Const(a) => None; diff --git a/src/content/1.10/code/reason/snippet16.re b/src/content/1.10/code/reason/snippet16.re new file mode 100644 index 000000000..14db1f232 --- /dev/null +++ b/src/content/1.10/code/reason/snippet16.re @@ -0,0 +1,2 @@ +type reader('e, 'a) = + | Reader('e => 'a); diff --git a/src/content/1.10/code/reason/snippet17.re b/src/content/1.10/code/reason/snippet17.re new file mode 100644 index 000000000..eb03ac61a --- /dev/null +++ b/src/content/1.10/code/reason/snippet17.re @@ -0,0 +1,8 @@ +module Reader_Functor = (T: {type e;}) : Functor => { + type t('a) = reader(T.e, 'a); + + let fmap: 'a 'b. ('a => 'b, t('a)) => t('b) = + f => + fun + | Reader(r) => Reader(compose(f, r)); +}; diff --git a/src/content/1.10/code/reason/snippet18.re b/src/content/1.10/code/reason/snippet18.re new file mode 100644 index 000000000..637c4258c --- /dev/null +++ b/src/content/1.10/code/reason/snippet18.re @@ -0,0 +1 @@ +let alpha: reader(unit, 'a) => option('a); diff --git a/src/content/1.10/code/reason/snippet19.re b/src/content/1.10/code/reason/snippet19.re new file mode 100644 index 000000000..e3f51dffd --- /dev/null +++ b/src/content/1.10/code/reason/snippet19.re @@ -0,0 +1,3 @@ +let dumb: 'a. reader(unit, 'a) => option('a) = + fun + | Reader(_) => None; diff --git a/src/content/1.10/code/reason/snippet20.re b/src/content/1.10/code/reason/snippet20.re new file mode 100644 index 000000000..bbeea0074 --- /dev/null +++ b/src/content/1.10/code/reason/snippet20.re @@ -0,0 +1,3 @@ +let obvious: 'a. reader(unit, 'a) => option('a) = + fun + | Reader(f) => Some(f()); diff --git a/src/content/1.10/code/reason/snippet21.re b/src/content/1.10/code/reason/snippet21.re new file mode 100644 index 000000000..0f76dedb6 --- /dev/null +++ b/src/content/1.10/code/reason/snippet21.re @@ -0,0 +1,2 @@ +type op('r, 'a) = + | Op('a => 'r); diff --git a/src/content/1.10/code/reason/snippet22.re b/src/content/1.10/code/reason/snippet22.re new file mode 100644 index 000000000..ccc841245 --- /dev/null +++ b/src/content/1.10/code/reason/snippet22.re @@ -0,0 +1,8 @@ +module Op_Contravariant = (T: {type r;}) : Contravariant => { + type t('a) = op(T.r, 'a); + + let contramap: ('b => 'a, t('a)) => t('b) = + f => + fun + | Op(g) => Op(compose(g, f)); +}; diff --git a/src/content/1.10/code/reason/snippet23.re b/src/content/1.10/code/reason/snippet23.re new file mode 100644 index 000000000..3558454b0 --- /dev/null +++ b/src/content/1.10/code/reason/snippet23.re @@ -0,0 +1,3 @@ +let pred_to_str = + fun + | Op(f) => Op(x => (f(x)) ? "T" : "F"); diff --git a/src/content/1.10/code/reason/snippet24.re b/src/content/1.10/code/reason/snippet24.re new file mode 100644 index 000000000..7b28cd0c8 --- /dev/null +++ b/src/content/1.10/code/reason/snippet24.re @@ -0,0 +1 @@ +compose(contramap(f), pred_to_str) == compose(pred_to_str, contramap(f)); diff --git a/src/content/1.10/code/reason/snippet25.re b/src/content/1.10/code/reason/snippet25.re new file mode 100644 index 000000000..894facda9 --- /dev/null +++ b/src/content/1.10/code/reason/snippet25.re @@ -0,0 +1,5 @@ +module Op_Bool = Op_Contravariant({type r = bool;}); + +let op_bool_contramap: ('b => 'a, Op_Bool.t('a)) => Op_Bool.t('b) = ( + Op_Bool.contramap: ('b => 'a, Op_Bool.t('a)) => Op_Bool.t('b) +); diff --git a/src/content/1.10/code/reason/snippet26.re b/src/content/1.10/code/reason/snippet26.re new file mode 100644 index 000000000..2029712be --- /dev/null +++ b/src/content/1.10/code/reason/snippet26.re @@ -0,0 +1 @@ +'a => 'a \ No newline at end of file diff --git a/src/content/1.10/code/reason/snippet27.re b/src/content/1.10/code/reason/snippet27.re new file mode 100644 index 000000000..0a8834f96 --- /dev/null +++ b/src/content/1.10/code/reason/snippet27.re @@ -0,0 +1 @@ +('a => 'a) => f('a) diff --git a/src/content/1.2/code/reason/snippet01.re b/src/content/1.2/code/reason/snippet01.re new file mode 100644 index 000000000..7b144b2e6 --- /dev/null +++ b/src/content/1.2/code/reason/snippet01.re @@ -0,0 +1 @@ +module type Chapter2_DeclareVariable = {let x: int;}; diff --git a/src/content/1.2/code/reason/snippet010.re b/src/content/1.2/code/reason/snippet010.re new file mode 100644 index 000000000..c0337460d --- /dev/null +++ b/src/content/1.2/code/reason/snippet010.re @@ -0,0 +1 @@ +let unit = _ => (); diff --git a/src/content/1.2/code/reason/snippet011.re b/src/content/1.2/code/reason/snippet011.re new file mode 100644 index 000000000..a2cd8fe32 --- /dev/null +++ b/src/content/1.2/code/reason/snippet011.re @@ -0,0 +1,3 @@ +type bool = + | false + | true; diff --git a/src/content/1.2/code/reason/snippet02.re b/src/content/1.2/code/reason/snippet02.re new file mode 100644 index 000000000..9f92cb7f0 --- /dev/null +++ b/src/content/1.2/code/reason/snippet02.re @@ -0,0 +1 @@ +module type Chapter2_DeclareFunction = {let f: bool => bool;}; diff --git a/src/content/1.2/code/reason/snippet03.re b/src/content/1.2/code/reason/snippet03.re new file mode 100644 index 000000000..9ccf7fa50 --- /dev/null +++ b/src/content/1.2/code/reason/snippet03.re @@ -0,0 +1,3 @@ +module Chapter2_Bottom: Chapter2_DeclareFunction = { + let f = (b: bool): bool => failwith("Not Implemented"); +}; diff --git a/src/content/1.2/code/reason/snippet04.re b/src/content/1.2/code/reason/snippet04.re new file mode 100644 index 000000000..4f97dfc0c --- /dev/null +++ b/src/content/1.2/code/reason/snippet04.re @@ -0,0 +1,3 @@ +module Chapter2_Bottom: Chapter2_DeclareFunction = { + let f: bool => bool = _ => failwith("Not implemented"); +}; \ No newline at end of file diff --git a/src/content/1.2/code/reason/snippet05.re b/src/content/1.2/code/reason/snippet05.re new file mode 100644 index 000000000..d259761d9 --- /dev/null +++ b/src/content/1.2/code/reason/snippet05.re @@ -0,0 +1 @@ +let fact = n => List.fold(List.range(1, n), ~init=1, ~f=( * )); diff --git a/src/content/1.2/code/reason/snippet06.re b/src/content/1.2/code/reason/snippet06.re new file mode 100644 index 000000000..51af1e94f --- /dev/null +++ b/src/content/1.2/code/reason/snippet06.re @@ -0,0 +1,3 @@ +type void; + +let rec absurd = (x: void) => absurd(x); diff --git a/src/content/1.2/code/reason/snippet07.re b/src/content/1.2/code/reason/snippet07.re new file mode 100644 index 000000000..6fa1f2178 --- /dev/null +++ b/src/content/1.2/code/reason/snippet07.re @@ -0,0 +1 @@ +let f44 = (): int => 44; diff --git a/src/content/1.2/code/reason/snippet08.re b/src/content/1.2/code/reason/snippet08.re new file mode 100644 index 000000000..eed1c70ad --- /dev/null +++ b/src/content/1.2/code/reason/snippet08.re @@ -0,0 +1 @@ +let f_int = (x: int) => (); diff --git a/src/content/1.2/code/reason/snippet09.re b/src/content/1.2/code/reason/snippet09.re new file mode 100644 index 000000000..7ea869bc4 --- /dev/null +++ b/src/content/1.2/code/reason/snippet09.re @@ -0,0 +1 @@ +let f_int = (_: int) => (); diff --git a/src/content/1.2/code/reason/snippet10.re b/src/content/1.2/code/reason/snippet10.re new file mode 100644 index 000000000..c0337460d --- /dev/null +++ b/src/content/1.2/code/reason/snippet10.re @@ -0,0 +1 @@ +let unit = _ => (); diff --git a/src/content/1.2/code/reason/snippet11.re b/src/content/1.2/code/reason/snippet11.re new file mode 100644 index 000000000..a2cd8fe32 --- /dev/null +++ b/src/content/1.2/code/reason/snippet11.re @@ -0,0 +1,3 @@ +type bool = + | false + | true; diff --git a/src/content/1.3/code/reason/snippet01.re b/src/content/1.3/code/reason/snippet01.re new file mode 100644 index 000000000..8fece00fb --- /dev/null +++ b/src/content/1.3/code/reason/snippet01.re @@ -0,0 +1,6 @@ +module type Monoid = { + type a; + + let mempty: a; + let mappend: (a, a) => a; +}; diff --git a/src/content/1.3/code/reason/snippet02.re b/src/content/1.3/code/reason/snippet02.re new file mode 100644 index 000000000..4cf2178bf --- /dev/null +++ b/src/content/1.3/code/reason/snippet02.re @@ -0,0 +1,6 @@ +module StringMonoid: Monoid = { + type a = string; + + let mempty = ""; + let mappend = (++); +}; diff --git a/src/content/1.4/code/reason/snippet01.re b/src/content/1.4/code/reason/snippet01.re new file mode 100644 index 000000000..47cecba69 --- /dev/null +++ b/src/content/1.4/code/reason/snippet01.re @@ -0,0 +1 @@ +type writer('a) = ('a, string); diff --git a/src/content/1.4/code/reason/snippet02.re b/src/content/1.4/code/reason/snippet02.re new file mode 100644 index 000000000..556274972 --- /dev/null +++ b/src/content/1.4/code/reason/snippet02.re @@ -0,0 +1 @@ +'a => writer('b) \ No newline at end of file diff --git a/src/content/1.4/code/reason/snippet03.re b/src/content/1.4/code/reason/snippet03.re new file mode 100644 index 000000000..7308f181a --- /dev/null +++ b/src/content/1.4/code/reason/snippet03.re @@ -0,0 +1,7 @@ +module type Kleisli = { + type a; + type b; + type c; + + let (>=>): (a => writer(b), b => writer(c), a) => writer(c); +}; diff --git a/src/content/1.4/code/reason/snippet04.re b/src/content/1.4/code/reason/snippet04.re new file mode 100644 index 000000000..e79f8aacc --- /dev/null +++ b/src/content/1.4/code/reason/snippet04.re @@ -0,0 +1 @@ +let pure = x => (x, ""); diff --git a/src/content/1.4/code/reason/snippet05.re b/src/content/1.4/code/reason/snippet05.re new file mode 100644 index 000000000..dcd0f1da2 --- /dev/null +++ b/src/content/1.4/code/reason/snippet05.re @@ -0,0 +1,2 @@ +let up_case: string => writer(string) = + s => (String.uppercase(s), "up_case "); \ No newline at end of file diff --git a/src/content/1.4/code/reason/snippet06.re b/src/content/1.4/code/reason/snippet06.re new file mode 100644 index 000000000..93cefe6c6 --- /dev/null +++ b/src/content/1.4/code/reason/snippet06.re @@ -0,0 +1,4 @@ +let to_words: string => writer(list(string)) = ( + s => (String.split(s, ~on=' '), "to_words "): + string => writer(list(string)) +); diff --git a/src/content/1.4/code/reason/snippet07.re b/src/content/1.4/code/reason/snippet07.re new file mode 100644 index 000000000..a8e94c02f --- /dev/null +++ b/src/content/1.4/code/reason/snippet07.re @@ -0,0 +1,10 @@ +module KleisiExample = + (K: Kleisli + with type a = string + and type b = string + and type c = list(string) + ) => { + let up_case_and_to_words: string => writer(list(string)) = ( + K.(>=>)(up_case, to_words): string => writer(list(string)) + ); +}; diff --git a/src/content/1.5/code/reason/snippet01.re b/src/content/1.5/code/reason/snippet01.re new file mode 100644 index 000000000..74b6ff1ab --- /dev/null +++ b/src/content/1.5/code/reason/snippet01.re @@ -0,0 +1,3 @@ +type void; /* Uninhabited type */ + +type absurd = void => 'a = ; diff --git a/src/content/1.5/code/reason/snippet02.re b/src/content/1.5/code/reason/snippet02.re new file mode 100644 index 000000000..3eb200c44 --- /dev/null +++ b/src/content/1.5/code/reason/snippet02.re @@ -0,0 +1 @@ +let unit = x => (); diff --git a/src/content/1.5/code/reason/snippet03.re b/src/content/1.5/code/reason/snippet03.re new file mode 100644 index 000000000..2c63ddd35 --- /dev/null +++ b/src/content/1.5/code/reason/snippet03.re @@ -0,0 +1 @@ +let yes = _ => true; diff --git a/src/content/1.5/code/reason/snippet04.re b/src/content/1.5/code/reason/snippet04.re new file mode 100644 index 000000000..004279347 --- /dev/null +++ b/src/content/1.5/code/reason/snippet04.re @@ -0,0 +1 @@ +let no = _ => false; diff --git a/src/content/1.5/code/reason/snippet05.re b/src/content/1.5/code/reason/snippet05.re new file mode 100644 index 000000000..6b1aa4a5f --- /dev/null +++ b/src/content/1.5/code/reason/snippet05.re @@ -0,0 +1,2 @@ +compose(f, g) == id; +compose(g, f) == id; diff --git a/src/content/1.5/code/reason/snippet06.re b/src/content/1.5/code/reason/snippet06.re new file mode 100644 index 000000000..28c87670b --- /dev/null +++ b/src/content/1.5/code/reason/snippet06.re @@ -0,0 +1 @@ +let fst = ((a, b)) => a; diff --git a/src/content/1.5/code/reason/snippet07.re b/src/content/1.5/code/reason/snippet07.re new file mode 100644 index 000000000..b93798444 --- /dev/null +++ b/src/content/1.5/code/reason/snippet07.re @@ -0,0 +1 @@ +let snd = ((a, b)) => b; diff --git a/src/content/1.5/code/reason/snippet08.re b/src/content/1.5/code/reason/snippet08.re new file mode 100644 index 000000000..a5e2fbda2 --- /dev/null +++ b/src/content/1.5/code/reason/snippet08.re @@ -0,0 +1,2 @@ +let fst = ((a, _)) => a; +let snd = ((_, b)) => b; diff --git a/src/content/1.5/code/reason/snippet09.re b/src/content/1.5/code/reason/snippet09.re new file mode 100644 index 000000000..acaccedb4 --- /dev/null +++ b/src/content/1.5/code/reason/snippet09.re @@ -0,0 +1,8 @@ +module type Chapter5_Product = { + type a; + type c; + type b; + + let p: c => a; + let q: c => b; +}; diff --git a/src/content/1.5/code/reason/snippet10.re b/src/content/1.5/code/reason/snippet10.re new file mode 100644 index 000000000..65662e525 --- /dev/null +++ b/src/content/1.5/code/reason/snippet10.re @@ -0,0 +1,12 @@ +module Chapter5_Product_Example: + Chapter5_Product + with type a = int + and type b = bool + and type c = int = { + type a = int; + type b = bool; + type c = int; + + let p = x => x; + let q = _ => true; +}; diff --git a/src/content/1.5/code/reason/snippet11.re b/src/content/1.5/code/reason/snippet11.re new file mode 100644 index 000000000..874be3a8a --- /dev/null +++ b/src/content/1.5/code/reason/snippet11.re @@ -0,0 +1,8 @@ +module Chapter5_Product_Example2: Chapter5_Product = { + type a = int; + type b = bool; + type c = (int, int, bool); + + let p = ((x, _, _)) => x; + let q = ((_, _, b)) => b; +}; diff --git a/src/content/1.5/code/reason/snippet12.re b/src/content/1.5/code/reason/snippet12.re new file mode 100644 index 000000000..07dc6fe36 --- /dev/null +++ b/src/content/1.5/code/reason/snippet12.re @@ -0,0 +1,2 @@ +let p' = compose(Chapter5_Product_Example.p, m); +let q' = compose(Chapter5_Product_Example.q, m); diff --git a/src/content/1.5/code/reason/snippet13.re b/src/content/1.5/code/reason/snippet13.re new file mode 100644 index 000000000..557f226ac --- /dev/null +++ b/src/content/1.5/code/reason/snippet13.re @@ -0,0 +1 @@ +let m = (x: int) => (x, true); diff --git a/src/content/1.5/code/reason/snippet14.re b/src/content/1.5/code/reason/snippet14.re new file mode 100644 index 000000000..fe8bd5cb9 --- /dev/null +++ b/src/content/1.5/code/reason/snippet14.re @@ -0,0 +1,2 @@ +let p = x => fst(m(x)); +let q = x => snd(m(x)); diff --git a/src/content/1.5/code/reason/snippet15.re b/src/content/1.5/code/reason/snippet15.re new file mode 100644 index 000000000..6eb97f275 --- /dev/null +++ b/src/content/1.5/code/reason/snippet15.re @@ -0,0 +1 @@ +let m = ((x, _, b): (int, int, bool)) => (x, b); diff --git a/src/content/1.5/code/reason/snippet16.re b/src/content/1.5/code/reason/snippet16.re new file mode 100644 index 000000000..b51daa0ab --- /dev/null +++ b/src/content/1.5/code/reason/snippet16.re @@ -0,0 +1,2 @@ +fst == compose(p, m'); +snd == compose(q, m'); diff --git a/src/content/1.5/code/reason/snippet17.re b/src/content/1.5/code/reason/snippet17.re new file mode 100644 index 000000000..34f42f307 --- /dev/null +++ b/src/content/1.5/code/reason/snippet17.re @@ -0,0 +1 @@ +let m' = ((x, b): (int, bool)) => (x, x, b); diff --git a/src/content/1.5/code/reason/snippet18.re b/src/content/1.5/code/reason/snippet18.re new file mode 100644 index 000000000..7ce4b15fe --- /dev/null +++ b/src/content/1.5/code/reason/snippet18.re @@ -0,0 +1 @@ +let m' = ((x, b): (int, bool)) => (x, 42, b); diff --git a/src/content/1.5/code/reason/snippet19.re b/src/content/1.5/code/reason/snippet19.re new file mode 100644 index 000000000..79941df89 --- /dev/null +++ b/src/content/1.5/code/reason/snippet19.re @@ -0,0 +1,8 @@ +module type Chapter5_product_projection_example = + (Product: Chapter5_Product) => { + let m: Product.c => (Product.a, Product.b); +}; + +module ProjectionImpl = (Product: Chapter5_Product) => { + let m = c => (Product.p(c), Product.q(c)); +}; diff --git a/src/content/1.5/code/reason/snippet20.re b/src/content/1.5/code/reason/snippet20.re new file mode 100644 index 000000000..efbf340a9 --- /dev/null +++ b/src/content/1.5/code/reason/snippet20.re @@ -0,0 +1,9 @@ +module type Factorizer = (Product: Chapter5_Product) => { + let factorizer: + (Product.c => Product.a, Product.c => Product.b, Product.c) => + (Product.a, Product.b); +}; + +module FactorizerImpl = (Product: Chapter5_Product) => { + let factorizer = (ca, cb) => (Product.p(ca), Product.q(cb)); +}; diff --git a/src/content/1.5/code/reason/snippet21.re b/src/content/1.5/code/reason/snippet21.re new file mode 100644 index 000000000..894f7a286 --- /dev/null +++ b/src/content/1.5/code/reason/snippet21.re @@ -0,0 +1,8 @@ +module type CoProduct = { + type a; + type b; + type c; + + let i: a => c; + let j: b => c; +}; diff --git a/src/content/1.5/code/reason/snippet22.re b/src/content/1.5/code/reason/snippet22.re new file mode 100644 index 000000000..9c9128e2a --- /dev/null +++ b/src/content/1.5/code/reason/snippet22.re @@ -0,0 +1,2 @@ +i' === compose(m, i) +j' === compose(m, j); diff --git a/src/content/1.5/code/reason/snippet23.re b/src/content/1.5/code/reason/snippet23.re new file mode 100644 index 000000000..5b9d3935e --- /dev/null +++ b/src/content/1.5/code/reason/snippet23.re @@ -0,0 +1,3 @@ +type contact = + | PhoneNum(int) + | EmailAddr(string); diff --git a/src/content/1.5/code/reason/snippet24.re b/src/content/1.5/code/reason/snippet24.re new file mode 100644 index 000000000..3d2da6ad1 --- /dev/null +++ b/src/content/1.5/code/reason/snippet24.re @@ -0,0 +1 @@ +let helpdesk = PhoneNum(2222222); diff --git a/src/content/1.5/code/reason/snippet25.re b/src/content/1.5/code/reason/snippet25.re new file mode 100644 index 000000000..d4e02be3f --- /dev/null +++ b/src/content/1.5/code/reason/snippet25.re @@ -0,0 +1,3 @@ +type either('a, 'b) = + | Left('a) + | Right('b); diff --git a/src/content/1.5/code/reason/snippet26.re b/src/content/1.5/code/reason/snippet26.re new file mode 100644 index 000000000..6c5485458 --- /dev/null +++ b/src/content/1.5/code/reason/snippet26.re @@ -0,0 +1,4 @@ +let factorizer = (i, j) => + fun + | Left(a) => i(a) + | Right(b) => j(b); diff --git a/src/content/1.5/code/reason/snippet27.re b/src/content/1.5/code/reason/snippet27.re new file mode 100644 index 000000000..e446b0e24 --- /dev/null +++ b/src/content/1.5/code/reason/snippet27.re @@ -0,0 +1,2 @@ +p == compose(fst, m); +q == compose(snd, m); diff --git a/src/content/1.5/code/reason/snippet28.re b/src/content/1.5/code/reason/snippet28.re new file mode 100644 index 000000000..002cfe8b4 --- /dev/null +++ b/src/content/1.5/code/reason/snippet28.re @@ -0,0 +1,2 @@ +p() == fst(m()); +q() == snd(m()); diff --git a/src/content/1.6/code/reason/snippet01.re b/src/content/1.6/code/reason/snippet01.re new file mode 100644 index 000000000..ab5d06644 --- /dev/null +++ b/src/content/1.6/code/reason/snippet01.re @@ -0,0 +1 @@ +let swap = ((a, b)) => (b, a); diff --git a/src/content/1.6/code/reason/snippet02.re b/src/content/1.6/code/reason/snippet02.re new file mode 100644 index 000000000..a25898ac4 --- /dev/null +++ b/src/content/1.6/code/reason/snippet02.re @@ -0,0 +1 @@ +(('a, 'b), 'c) \ No newline at end of file diff --git a/src/content/1.6/code/reason/snippet03.re b/src/content/1.6/code/reason/snippet03.re new file mode 100644 index 000000000..c143d5cb9 --- /dev/null +++ b/src/content/1.6/code/reason/snippet03.re @@ -0,0 +1 @@ +('a, ('b, 'c)) \ No newline at end of file diff --git a/src/content/1.6/code/reason/snippet04.re b/src/content/1.6/code/reason/snippet04.re new file mode 100644 index 000000000..3dc8e57e7 --- /dev/null +++ b/src/content/1.6/code/reason/snippet04.re @@ -0,0 +1 @@ +let alpha = (((a, b), c)) => (a, (b, c)); diff --git a/src/content/1.6/code/reason/snippet05.re b/src/content/1.6/code/reason/snippet05.re new file mode 100644 index 000000000..994b06ab9 --- /dev/null +++ b/src/content/1.6/code/reason/snippet05.re @@ -0,0 +1 @@ +let alpha_inv = ((a, (b, c))) => ((a, b), c); diff --git a/src/content/1.6/code/reason/snippet06.re b/src/content/1.6/code/reason/snippet06.re new file mode 100644 index 000000000..94f6276cf --- /dev/null +++ b/src/content/1.6/code/reason/snippet06.re @@ -0,0 +1 @@ +('a, unit) \ No newline at end of file diff --git a/src/content/1.6/code/reason/snippet07.re b/src/content/1.6/code/reason/snippet07.re new file mode 100644 index 000000000..9b643c834 --- /dev/null +++ b/src/content/1.6/code/reason/snippet07.re @@ -0,0 +1 @@ +let rho = ((a, ())) => a; diff --git a/src/content/1.6/code/reason/snippet08.re b/src/content/1.6/code/reason/snippet08.re new file mode 100644 index 000000000..82ccc5296 --- /dev/null +++ b/src/content/1.6/code/reason/snippet08.re @@ -0,0 +1 @@ +let rho_inv = a => (a, ()); diff --git a/src/content/1.6/code/reason/snippet09.re b/src/content/1.6/code/reason/snippet09.re new file mode 100644 index 000000000..23d91202f --- /dev/null +++ b/src/content/1.6/code/reason/snippet09.re @@ -0,0 +1,2 @@ +type pair('a, 'b) = + | P('a, 'b); diff --git a/src/content/1.6/code/reason/snippet10.re b/src/content/1.6/code/reason/snippet10.re new file mode 100644 index 000000000..66c4cbbc4 --- /dev/null +++ b/src/content/1.6/code/reason/snippet10.re @@ -0,0 +1 @@ +let stmt = P("This statement is", false); diff --git a/src/content/1.6/code/reason/snippet11.re b/src/content/1.6/code/reason/snippet11.re new file mode 100644 index 000000000..8e56c34f4 --- /dev/null +++ b/src/content/1.6/code/reason/snippet11.re @@ -0,0 +1,2 @@ +type pair('a, 'b) = + | Pair(('a, 'b)); diff --git a/src/content/1.6/code/reason/snippet12.re b/src/content/1.6/code/reason/snippet12.re new file mode 100644 index 000000000..3bd761849 --- /dev/null +++ b/src/content/1.6/code/reason/snippet12.re @@ -0,0 +1 @@ +let stmt = ("This statement is", false); diff --git a/src/content/1.6/code/reason/snippet13.re b/src/content/1.6/code/reason/snippet13.re new file mode 100644 index 000000000..bdea7ac7d --- /dev/null +++ b/src/content/1.6/code/reason/snippet13.re @@ -0,0 +1,2 @@ +type stmt = + | Stmt(string, int); diff --git a/src/content/1.6/code/reason/snippet14.re b/src/content/1.6/code/reason/snippet14.re new file mode 100644 index 000000000..972ecff5e --- /dev/null +++ b/src/content/1.6/code/reason/snippet14.re @@ -0,0 +1,2 @@ +let starts_with_symbol = ((name, symbol, _)) => + String.is_prefix(name, ~prefix=symbol); diff --git a/src/content/1.6/code/reason/snippet15.re b/src/content/1.6/code/reason/snippet15.re new file mode 100644 index 000000000..7024119b3 --- /dev/null +++ b/src/content/1.6/code/reason/snippet15.re @@ -0,0 +1,5 @@ +type element = { + name: string, + symbol: string, + atomic_number: int, +}; diff --git a/src/content/1.6/code/reason/snippet16.re b/src/content/1.6/code/reason/snippet16.re new file mode 100644 index 000000000..41c4c14b3 --- /dev/null +++ b/src/content/1.6/code/reason/snippet16.re @@ -0,0 +1,5 @@ +let tuple_to_elem = ((name, symbol, atomic_number)) => { + name, + symbol, + atomic_number, +}; diff --git a/src/content/1.6/code/reason/snippet17.re b/src/content/1.6/code/reason/snippet17.re new file mode 100644 index 000000000..abbc0cb81 --- /dev/null +++ b/src/content/1.6/code/reason/snippet17.re @@ -0,0 +1,5 @@ +let elem_to_tuple = ({name, symbol, atomic_number}) => ( + name, + symbol, + atomic_number, +); diff --git a/src/content/1.6/code/reason/snippet18.re b/src/content/1.6/code/reason/snippet18.re new file mode 100644 index 000000000..cbf12a95e --- /dev/null +++ b/src/content/1.6/code/reason/snippet18.re @@ -0,0 +1 @@ +let atomic_number = ({atomic_number}) => atomic_number; diff --git a/src/content/1.6/code/reason/snippet19.re b/src/content/1.6/code/reason/snippet19.re new file mode 100644 index 000000000..615593965 --- /dev/null +++ b/src/content/1.6/code/reason/snippet19.re @@ -0,0 +1,2 @@ +let starts_with_symbol = ({name, symbol, _}) => + String.is_prefix(name, ~prefix=symbol); diff --git a/src/content/1.6/code/reason/snippet20.re b/src/content/1.6/code/reason/snippet20.re new file mode 100644 index 000000000..16544a5a6 --- /dev/null +++ b/src/content/1.6/code/reason/snippet20.re @@ -0,0 +1,2 @@ +// ReasonML only allows special characters in the infix operator. +// So, the above function name cannot be applied as infix. diff --git a/src/content/1.6/code/reason/snippet21.re b/src/content/1.6/code/reason/snippet21.re new file mode 100644 index 000000000..d4e02be3f --- /dev/null +++ b/src/content/1.6/code/reason/snippet21.re @@ -0,0 +1,3 @@ +type either('a, 'b) = + | Left('a) + | Right('b); diff --git a/src/content/1.6/code/reason/snippet22.re b/src/content/1.6/code/reason/snippet22.re new file mode 100644 index 000000000..bd874ff81 --- /dev/null +++ b/src/content/1.6/code/reason/snippet22.re @@ -0,0 +1,4 @@ +type one_of_three('a, 'b, 'c) = + | Sinistrial('a) + | Medial('b) + | Dextral('c); diff --git a/src/content/1.6/code/reason/snippet23.re b/src/content/1.6/code/reason/snippet23.re new file mode 100644 index 000000000..a2c9fdc6b --- /dev/null +++ b/src/content/1.6/code/reason/snippet23.re @@ -0,0 +1 @@ +either('a, void) \ No newline at end of file diff --git a/src/content/1.6/code/reason/snippet24.re b/src/content/1.6/code/reason/snippet24.re new file mode 100644 index 000000000..3a41e26c5 --- /dev/null +++ b/src/content/1.6/code/reason/snippet24.re @@ -0,0 +1,4 @@ +type color = + | Red + | Green + | Blue; diff --git a/src/content/1.6/code/reason/snippet25.re b/src/content/1.6/code/reason/snippet25.re new file mode 100644 index 000000000..95667ef4a --- /dev/null +++ b/src/content/1.6/code/reason/snippet25.re @@ -0,0 +1,3 @@ +type bool = + | True + | False; diff --git a/src/content/1.6/code/reason/snippet26.re b/src/content/1.6/code/reason/snippet26.re new file mode 100644 index 000000000..b9898d29c --- /dev/null +++ b/src/content/1.6/code/reason/snippet26.re @@ -0,0 +1,3 @@ +type maybe('a) = + | Nothing + | Just('a); diff --git a/src/content/1.6/code/reason/snippet27.re b/src/content/1.6/code/reason/snippet27.re new file mode 100644 index 000000000..8328eadcf --- /dev/null +++ b/src/content/1.6/code/reason/snippet27.re @@ -0,0 +1,2 @@ +type nothing_type = + | Nothing; diff --git a/src/content/1.6/code/reason/snippet28.re b/src/content/1.6/code/reason/snippet28.re new file mode 100644 index 000000000..1f8e15467 --- /dev/null +++ b/src/content/1.6/code/reason/snippet28.re @@ -0,0 +1,2 @@ +type just_type('a) = + | Just('a); diff --git a/src/content/1.6/code/reason/snippet29.re b/src/content/1.6/code/reason/snippet29.re new file mode 100644 index 000000000..cc7e6d6d8 --- /dev/null +++ b/src/content/1.6/code/reason/snippet29.re @@ -0,0 +1 @@ +type maybe('a) = either(unit, 'a); diff --git a/src/content/1.6/code/reason/snippet30.re b/src/content/1.6/code/reason/snippet30.re new file mode 100644 index 000000000..ee3f7ddfb --- /dev/null +++ b/src/content/1.6/code/reason/snippet30.re @@ -0,0 +1,3 @@ +type list('a) = + | Nil + | Cons('a, list('a)); diff --git a/src/content/1.6/code/reason/snippet31.re b/src/content/1.6/code/reason/snippet31.re new file mode 100644 index 000000000..b4fdfd2bf --- /dev/null +++ b/src/content/1.6/code/reason/snippet31.re @@ -0,0 +1,8 @@ +type maybe('a) = + | Nothing + | Just('a); + +let maybe_tail = + fun + | Nil => Nothing + | Cons(_, xs) => Just(xs); diff --git a/src/content/1.6/code/reason/snippet32.re b/src/content/1.6/code/reason/snippet32.re new file mode 100644 index 000000000..e9eaae809 --- /dev/null +++ b/src/content/1.6/code/reason/snippet32.re @@ -0,0 +1 @@ +('a, either('b, 'c)) \ No newline at end of file diff --git a/src/content/1.6/code/reason/snippet33.re b/src/content/1.6/code/reason/snippet33.re new file mode 100644 index 000000000..4f7fb01c1 --- /dev/null +++ b/src/content/1.6/code/reason/snippet33.re @@ -0,0 +1 @@ +either(('a, 'b), ('c, 'd)) \ No newline at end of file diff --git a/src/content/1.6/code/reason/snippet34.re b/src/content/1.6/code/reason/snippet34.re new file mode 100644 index 000000000..55287207e --- /dev/null +++ b/src/content/1.6/code/reason/snippet34.re @@ -0,0 +1,5 @@ +let prod_to_sum = ((x, e)) => + switch (e) { + | Left(y) => Left(x, y) + | Right(z) => Right(x, z) + }; diff --git a/src/content/1.6/code/reason/snippet35.re b/src/content/1.6/code/reason/snippet35.re new file mode 100644 index 000000000..a0983b905 --- /dev/null +++ b/src/content/1.6/code/reason/snippet35.re @@ -0,0 +1,4 @@ +let sum_to_prod = + fun + | Left(x, y) => (x, Left(y)) + | Right(x, z) => (x, Right(z)); diff --git a/src/content/1.6/code/reason/snippet36.re b/src/content/1.6/code/reason/snippet36.re new file mode 100644 index 000000000..216b9de6e --- /dev/null +++ b/src/content/1.6/code/reason/snippet36.re @@ -0,0 +1 @@ +let prod1 = (2, Left("Hi!")); diff --git a/src/content/1.6/code/reason/snippet37.re b/src/content/1.6/code/reason/snippet37.re new file mode 100644 index 000000000..ee3f7ddfb --- /dev/null +++ b/src/content/1.6/code/reason/snippet37.re @@ -0,0 +1,3 @@ +type list('a) = + | Nil + | Cons('a, list('a)); diff --git a/src/content/1.7/code/reason/snippet01.re b/src/content/1.7/code/reason/snippet01.re new file mode 100644 index 000000000..aa1e044b2 --- /dev/null +++ b/src/content/1.7/code/reason/snippet01.re @@ -0,0 +1 @@ +let compose = (f, g, x) => f(g(x)); diff --git a/src/content/1.7/code/reason/snippet02.re b/src/content/1.7/code/reason/snippet02.re new file mode 100644 index 000000000..78fde77e7 --- /dev/null +++ b/src/content/1.7/code/reason/snippet02.re @@ -0,0 +1,3 @@ +type option('a) = + | None + | Some('a); diff --git a/src/content/1.7/code/reason/snippet03.re b/src/content/1.7/code/reason/snippet03.re new file mode 100644 index 000000000..c4bfb9cc8 --- /dev/null +++ b/src/content/1.7/code/reason/snippet03.re @@ -0,0 +1,6 @@ +module type AtoB = { + type a; + type b; + + let f: a => b; +}; diff --git a/src/content/1.7/code/reason/snippet04.re b/src/content/1.7/code/reason/snippet04.re new file mode 100644 index 000000000..0a21e2398 --- /dev/null +++ b/src/content/1.7/code/reason/snippet04.re @@ -0,0 +1,4 @@ +let f' = f => + fun + | None => None + | Some(x) => Some(f(x)); diff --git a/src/content/1.7/code/reason/snippet05.re b/src/content/1.7/code/reason/snippet05.re new file mode 100644 index 000000000..b507d57d7 --- /dev/null +++ b/src/content/1.7/code/reason/snippet05.re @@ -0,0 +1,6 @@ +module type Maybe_Functor = { + type a; + type b; + + let fmap: (a => b, option(a)) => option(b); +}; diff --git a/src/content/1.7/code/reason/snippet06.re b/src/content/1.7/code/reason/snippet06.re new file mode 100644 index 000000000..b507d57d7 --- /dev/null +++ b/src/content/1.7/code/reason/snippet06.re @@ -0,0 +1,6 @@ +module type Maybe_Functor = { + type a; + type b; + + let fmap: (a => b, option(a)) => option(b); +}; diff --git a/src/content/1.7/code/reason/snippet07.re b/src/content/1.7/code/reason/snippet07.re new file mode 100644 index 000000000..a34ce8c1d --- /dev/null +++ b/src/content/1.7/code/reason/snippet07.re @@ -0,0 +1,4 @@ +let fmap = f => + fun + | None => None + | Some(x) => Some(f(x)); diff --git a/src/content/1.7/code/reason/snippet08.re b/src/content/1.7/code/reason/snippet08.re new file mode 100644 index 000000000..0dab30dc4 --- /dev/null +++ b/src/content/1.7/code/reason/snippet08.re @@ -0,0 +1 @@ +let id = x => x; diff --git a/src/content/1.7/code/reason/snippet09.re b/src/content/1.7/code/reason/snippet09.re new file mode 100644 index 000000000..7d2d797cd --- /dev/null +++ b/src/content/1.7/code/reason/snippet09.re @@ -0,0 +1,5 @@ +module Test_Functor_Id = (F: Functor) => { + open F; + + let test_id = x => assert(fmap(id, x) == x); +}; diff --git a/src/content/1.7/code/reason/snippet10.re b/src/content/1.7/code/reason/snippet10.re new file mode 100644 index 000000000..8f8b28d78 --- /dev/null +++ b/src/content/1.7/code/reason/snippet10.re @@ -0,0 +1,9 @@ +module Test_Functor_Compose = (F: Functor) => { + open F; + + /* Compose */ + let (<.>) = (f, g, x) => f(g(x)); + + let test_compose = (f, g, x) => + assert(fmap(f <.> g, x) == fmap(f, fmap(g, x))); +}; diff --git a/src/content/1.7/code/reason/snippet11.re b/src/content/1.7/code/reason/snippet11.re new file mode 100644 index 000000000..9b94ccbdd --- /dev/null +++ b/src/content/1.7/code/reason/snippet11.re @@ -0,0 +1,5 @@ +module type Eq = { + type a; + + let (===): (a, a) => bool; +}; diff --git a/src/content/1.7/code/reason/snippet12.re b/src/content/1.7/code/reason/snippet12.re new file mode 100644 index 000000000..ac3d80af1 --- /dev/null +++ b/src/content/1.7/code/reason/snippet12.re @@ -0,0 +1,2 @@ +type point = + | Pt(float, float); diff --git a/src/content/1.7/code/reason/snippet13.re b/src/content/1.7/code/reason/snippet13.re new file mode 100644 index 000000000..531d74278 --- /dev/null +++ b/src/content/1.7/code/reason/snippet13.re @@ -0,0 +1,6 @@ +module Point_Eq = (E: Eq with type a = float) => { + type a = point; + + let (===) = (Pt(p1x, p1y), Pt(p2x, p2y)) => + E.(p1x === p2x) && E.(p2x === p2y); +}; diff --git a/src/content/1.7/code/reason/snippet14.re b/src/content/1.7/code/reason/snippet14.re new file mode 100644 index 000000000..da5a4bbc1 --- /dev/null +++ b/src/content/1.7/code/reason/snippet14.re @@ -0,0 +1,5 @@ +module type Functor = { + type t('a); + + let fmap: ('a => 'b, t('a)) => t('b); +}; diff --git a/src/content/1.7/code/reason/snippet15.re b/src/content/1.7/code/reason/snippet15.re new file mode 100644 index 000000000..a91405167 --- /dev/null +++ b/src/content/1.7/code/reason/snippet15.re @@ -0,0 +1,8 @@ +module Option_Functor: Functor with type t('a) = option('a) = { + type t('a) = option('a); + + let fmap = f => + fun + | None => None + | Some(x) => Some(f(x)); +}; diff --git a/src/content/1.7/code/reason/snippet16.re b/src/content/1.7/code/reason/snippet16.re new file mode 100644 index 000000000..ee3f7ddfb --- /dev/null +++ b/src/content/1.7/code/reason/snippet16.re @@ -0,0 +1,3 @@ +type list('a) = + | Nil + | Cons('a, list('a)); diff --git a/src/content/1.7/code/reason/snippet17.re b/src/content/1.7/code/reason/snippet17.re new file mode 100644 index 000000000..99c404975 --- /dev/null +++ b/src/content/1.7/code/reason/snippet17.re @@ -0,0 +1,5 @@ +module type List_Functor_Type = { + type t('a) = list('a); + + let fmap: ('a => 'b, list('a)) => list('b); +}; diff --git a/src/content/1.7/code/reason/snippet18.re b/src/content/1.7/code/reason/snippet18.re new file mode 100644 index 000000000..ff3665d2a --- /dev/null +++ b/src/content/1.7/code/reason/snippet18.re @@ -0,0 +1,4 @@ +let rec fmap = f => + fun + | Nil => Nil + | Cons(x, xs) => Cons(f(x), fmap(f, xs)); diff --git a/src/content/1.7/code/reason/snippet19.re b/src/content/1.7/code/reason/snippet19.re new file mode 100644 index 000000000..534179b08 --- /dev/null +++ b/src/content/1.7/code/reason/snippet19.re @@ -0,0 +1,8 @@ +module List_Functor: Functor with type t('a) = list('a) = { + type t('a) = list('a); + + let rec fmap = f => + fun + | Nil => Nil + | Cons(x, xs) => Cons(f(x), fmap(f, xs)); +}; diff --git a/src/content/1.7/code/reason/snippet20.re b/src/content/1.7/code/reason/snippet20.re new file mode 100644 index 000000000..6a612da92 --- /dev/null +++ b/src/content/1.7/code/reason/snippet20.re @@ -0,0 +1 @@ +type t('a, 'b) = 'a => 'b; diff --git a/src/content/1.7/code/reason/snippet21.re b/src/content/1.7/code/reason/snippet21.re new file mode 100644 index 000000000..e166bf3b5 --- /dev/null +++ b/src/content/1.7/code/reason/snippet21.re @@ -0,0 +1,5 @@ +module type T = {type t;}; + +module Partially_Applied_FunctionType = (T: T) => { + type t('b) = T.t => 'b; +}; diff --git a/src/content/1.7/code/reason/snippet22.re b/src/content/1.7/code/reason/snippet22.re new file mode 100644 index 000000000..6ebff5c16 --- /dev/null +++ b/src/content/1.7/code/reason/snippet22.re @@ -0,0 +1,3 @@ +module type Reader_Fmap_Example = { + let fmap: ('a => 'b, 'r => 'a, 'r) => 'b; +}; diff --git a/src/content/1.7/code/reason/snippet23.re b/src/content/1.7/code/reason/snippet23.re new file mode 100644 index 000000000..481d27e31 --- /dev/null +++ b/src/content/1.7/code/reason/snippet23.re @@ -0,0 +1,5 @@ +module Reader_Functor = (T: T) : Functor => { + type t('a) = T.t => 'a; + + let fmap = (f, ra, r) => f(ra(r)); +}; diff --git a/src/content/1.7/code/reason/snippet24.re b/src/content/1.7/code/reason/snippet24.re new file mode 100644 index 000000000..a6dbac7a8 --- /dev/null +++ b/src/content/1.7/code/reason/snippet24.re @@ -0,0 +1,3 @@ +let fmap: ('a => 'b, 'r => 'a, 'r) => 'b = ( + compose: ('a => 'b, 'r => 'a, 'r) => 'b +); diff --git a/src/content/1.7/code/reason/snippet25.re b/src/content/1.7/code/reason/snippet25.re new file mode 100644 index 000000000..f1a3e0fa7 --- /dev/null +++ b/src/content/1.7/code/reason/snippet25.re @@ -0,0 +1 @@ +let nats = Caml.Stream.from(i => Some(i + 1)); diff --git a/src/content/1.7/code/reason/snippet26.re b/src/content/1.7/code/reason/snippet26.re new file mode 100644 index 000000000..72bbc5bf1 --- /dev/null +++ b/src/content/1.7/code/reason/snippet26.re @@ -0,0 +1,2 @@ +type const('c, 'a) = + | Const('c); diff --git a/src/content/1.7/code/reason/snippet27.re b/src/content/1.7/code/reason/snippet27.re new file mode 100644 index 000000000..4fd6ab09c --- /dev/null +++ b/src/content/1.7/code/reason/snippet27.re @@ -0,0 +1,3 @@ +module type Const_Functor_Example = { + let fmap: ('a => 'b, const('c, 'a)) => const('c, 'b); +}; diff --git a/src/content/1.7/code/reason/snippet28.re b/src/content/1.7/code/reason/snippet28.re new file mode 100644 index 000000000..e6a49a849 --- /dev/null +++ b/src/content/1.7/code/reason/snippet28.re @@ -0,0 +1,6 @@ +module Const_Functor = (T: T) : Functor => { + type t('a) = const(T.t, 'a); + + // or even let fmap = (_, c) => c; + let fmap = (f, Const(c)) => Const(c); +}; diff --git a/src/content/1.7/code/reason/snippet29.re b/src/content/1.7/code/reason/snippet29.re new file mode 100644 index 000000000..f1fc0e30a --- /dev/null +++ b/src/content/1.7/code/reason/snippet29.re @@ -0,0 +1,4 @@ +let maybe_tail = + fun + | [] => None + | [_, ...xs] => Some(xs); diff --git a/src/content/1.7/code/reason/snippet30.re b/src/content/1.7/code/reason/snippet30.re new file mode 100644 index 000000000..95f2bfcae --- /dev/null +++ b/src/content/1.7/code/reason/snippet30.re @@ -0,0 +1,3 @@ +let square = x => x * x; +let mis = Some(Cons(1, Cons(2, Cons(3, Nil)))); +let mis2 = Option_Functor.fmap(List_Functor.fmap(square), mis); diff --git a/src/content/1.7/code/reason/snippet31.re b/src/content/1.7/code/reason/snippet31.re new file mode 100644 index 000000000..cb97428e2 --- /dev/null +++ b/src/content/1.7/code/reason/snippet31.re @@ -0,0 +1,4 @@ +let fmapO = Option_Functor.fmap; +let fmapL = List_Functor.fmap; +let fmapC = (f, l) => (compose(fmapO, fmapL))(f, l); +let mis2 = fmapC(square, mis); diff --git a/src/content/1.7/code/reason/snippet32.re b/src/content/1.7/code/reason/snippet32.re new file mode 100644 index 000000000..c97fb0ffd --- /dev/null +++ b/src/content/1.7/code/reason/snippet32.re @@ -0,0 +1,5 @@ +module type Fmap_Alt_Sig_Example = { + type t('a); + + let fmap: ('a => 'b, t('a)) => t('b); +}; diff --git a/src/content/1.7/code/reason/snippet33.re b/src/content/1.7/code/reason/snippet33.re new file mode 100644 index 000000000..d5b003e52 --- /dev/null +++ b/src/content/1.7/code/reason/snippet33.re @@ -0,0 +1 @@ +module type Square_Signature = {let square: int => int;}; diff --git a/src/content/1.7/code/reason/snippet34.re b/src/content/1.7/code/reason/snippet34.re new file mode 100644 index 000000000..0212843c0 --- /dev/null +++ b/src/content/1.7/code/reason/snippet34.re @@ -0,0 +1 @@ +list(int) => list(int) \ No newline at end of file diff --git a/src/content/1.7/code/reason/snippet35.re b/src/content/1.7/code/reason/snippet35.re new file mode 100644 index 000000000..dcb6702cc --- /dev/null +++ b/src/content/1.7/code/reason/snippet35.re @@ -0,0 +1 @@ +option(list(int)) => option(list(int)) \ No newline at end of file diff --git a/src/content/1.8/code/reason/snippet01.re b/src/content/1.8/code/reason/snippet01.re new file mode 100644 index 000000000..79fd602aa --- /dev/null +++ b/src/content/1.8/code/reason/snippet01.re @@ -0,0 +1,27 @@ +/** You can represent bifunctor defintion in two forms + * and implement just and derive the other from it. */ +module type BifunctorCore = { + type t('a, 'b); + + let bimap: ('a => 'c, 'b => 'd, t('a, 'b)) => t('c, 'd); +}; + +module type BifunctorExt = { + type t('a, 'b); + + let first: ('a => 'c, t('a, 'b)) => t('c, 'b); + let second: ('b => 'd, t('a, 'b)) => t('a, 'd); +}; + +module BifunctorCore_Using_Ext = (M: BifunctorExt) : BifunctorCore => { + type t('a, 'b) = M.t('a, 'b); + + let bimap = (g, h, x) => M.first(g, M.second(h, x)); +}; + +module BifunctorExt_Using_Core = (M: BifunctorCore) : BifunctorExt => { + type t('a, 'b) = M.t('a, 'b); + + let first = (g, x) => M.bimap(g, id, x); + let second = (h, x) => M.bimap(id, h, x); +}; diff --git a/src/content/1.8/code/reason/snippet02.re b/src/content/1.8/code/reason/snippet02.re new file mode 100644 index 000000000..d6d31b325 --- /dev/null +++ b/src/content/1.8/code/reason/snippet02.re @@ -0,0 +1,5 @@ +module Bifunctor_Product: BifunctorCore = { + type t('a, 'b) = ('a, 'b); + + let bimap = (f, g, (l, r)) => (f(l), g(r)); +}; diff --git a/src/content/1.8/code/reason/snippet03.re b/src/content/1.8/code/reason/snippet03.re new file mode 100644 index 000000000..5570a8824 --- /dev/null +++ b/src/content/1.8/code/reason/snippet03.re @@ -0,0 +1,2 @@ +let bimap: ('a => 'c, 'b => 'd, Bifunctor_Product.t('a, 'b)) => + Bifunctor_Product.t('c, 'd) \ No newline at end of file diff --git a/src/content/1.8/code/reason/snippet04.re b/src/content/1.8/code/reason/snippet04.re new file mode 100644 index 000000000..b14b3ed55 --- /dev/null +++ b/src/content/1.8/code/reason/snippet04.re @@ -0,0 +1,12 @@ +type either('a, 'b) = + | Left('a) + | Right('b); + +module Bifunctor_Either: BifunctorCore = { + type t('a, 'b) = either('a, 'b); + + let bimap = (f, g) => + fun + | Left(a) => Left(f(a)) + | Right(b) => Right(g(b)); +}; diff --git a/src/content/1.8/code/reason/snippet05.re b/src/content/1.8/code/reason/snippet05.re new file mode 100644 index 000000000..39b20a47d --- /dev/null +++ b/src/content/1.8/code/reason/snippet05.re @@ -0,0 +1,2 @@ +type id('a) = + | Id('a); diff --git a/src/content/1.8/code/reason/snippet06.re b/src/content/1.8/code/reason/snippet06.re new file mode 100644 index 000000000..5385b5426 --- /dev/null +++ b/src/content/1.8/code/reason/snippet06.re @@ -0,0 +1,5 @@ +module Identity_Functor: Functor = { + type t('a) = id('a); + + let fmap = (f, Id(a)) => Id(f(a)); +}; diff --git a/src/content/1.8/code/reason/snippet07.re b/src/content/1.8/code/reason/snippet07.re new file mode 100644 index 000000000..78fde77e7 --- /dev/null +++ b/src/content/1.8/code/reason/snippet07.re @@ -0,0 +1,3 @@ +type option('a) = + | None + | Some('a); diff --git a/src/content/1.8/code/reason/snippet08.re b/src/content/1.8/code/reason/snippet08.re new file mode 100644 index 000000000..d5ed628a9 --- /dev/null +++ b/src/content/1.8/code/reason/snippet08.re @@ -0,0 +1,11 @@ +/* ReasonML doesn't have a built in Const type */ +type const('a, 'b) = + | Const('a); + +/* ReasonML doesn't have a built in either type */ +type either('a, 'b) = + | Left('a) + | Right('b); + +/* Either type */ +type option('a) = either(const(unit, 'a), id('a)); diff --git a/src/content/1.8/code/reason/snippet09.re b/src/content/1.8/code/reason/snippet09.re new file mode 100644 index 000000000..2aed101e9 --- /dev/null +++ b/src/content/1.8/code/reason/snippet09.re @@ -0,0 +1,13 @@ +/** ReasonML doesn't support higher kinded types. + * So, we have to use module functors to emulate the behavior higher kinded types. + * There's less verbose options using type defunctionalization + * but it's more advanced and obscures the flow of this book */ +module type BiComp = + ( + BF: {type t('a, 'b);}, + FU: {type t('a);}, + GU: {type t('b);} + ) => { + type bicomp('a, 'b) = + | BiComp(BF.t(FU.t('a), GU.t('b))); + }; diff --git a/src/content/1.8/code/reason/snippet10.re b/src/content/1.8/code/reason/snippet10.re new file mode 100644 index 000000000..5fe0777c8 --- /dev/null +++ b/src/content/1.8/code/reason/snippet10.re @@ -0,0 +1,12 @@ +module BiCompBifunctor = + ( + BF: BifunctorCore, + FU: Functor, + GU: Functor + ): BifunctorCore => { + type t('a, 'b) = + | BiComp(BF.t(FU.t('a), GU.t('b))); + + let bimap = (f, g, BiComp(x)) => + BiComp(BF.bimap(FU.fmap(f), GU.fmap(g), x)); +}; diff --git a/src/content/1.8/code/reason/snippet11.re b/src/content/1.8/code/reason/snippet11.re new file mode 100644 index 000000000..fa814783a --- /dev/null +++ b/src/content/1.8/code/reason/snippet11.re @@ -0,0 +1 @@ +BF.t(FU.t('a), GU.t('b)); \ No newline at end of file diff --git a/src/content/1.8/code/reason/snippet12.re b/src/content/1.8/code/reason/snippet12.re new file mode 100644 index 000000000..59145fcda --- /dev/null +++ b/src/content/1.8/code/reason/snippet12.re @@ -0,0 +1,2 @@ +let f1: a => a' +let f2: b => b' \ No newline at end of file diff --git a/src/content/1.8/code/reason/snippet13.re b/src/content/1.8/code/reason/snippet13.re new file mode 100644 index 000000000..f2796a2c1 --- /dev/null +++ b/src/content/1.8/code/reason/snippet13.re @@ -0,0 +1,2 @@ +let bimap: (FU.t(a) => FU.t(a')) => (GU.t(b) => GU.t(b')) => + (FU.t(a), GU.t(b)) => (FU.t(a'), GU.t(b')) \ No newline at end of file diff --git a/src/content/1.8/code/reason/snippet14.re b/src/content/1.8/code/reason/snippet14.re new file mode 100644 index 000000000..158f88cec --- /dev/null +++ b/src/content/1.8/code/reason/snippet14.re @@ -0,0 +1,6 @@ +/** Deriving a functor in ReasonML is not available as a + * language extension. You could try experimental library + * like ocsigen to derive functors.*/ +type tree('a) = + | Leaf('a) + | Node(tree('a), tree('a)); diff --git a/src/content/1.8/code/reason/snippet15.re b/src/content/1.8/code/reason/snippet15.re new file mode 100644 index 000000000..9da9477b2 --- /dev/null +++ b/src/content/1.8/code/reason/snippet15.re @@ -0,0 +1,8 @@ +module TreeFunctor: Functor = { + type t('a) = tree('a); + + let rec fmap = f => + fun + | Leaf(a) => Leaf(f(a)) + | Node(l, r) => Node(fmap(f, l), fmap(f, r)); +}; diff --git a/src/content/1.8/code/reason/snippet16.re b/src/content/1.8/code/reason/snippet16.re new file mode 100644 index 000000000..47cecba69 --- /dev/null +++ b/src/content/1.8/code/reason/snippet16.re @@ -0,0 +1 @@ +type writer('a) = ('a, string); diff --git a/src/content/1.8/code/reason/snippet17.re b/src/content/1.8/code/reason/snippet17.re new file mode 100644 index 000000000..e23e22402 --- /dev/null +++ b/src/content/1.8/code/reason/snippet17.re @@ -0,0 +1,8 @@ +module KleisliComposition = { + let (>=>): ('a => writer('b), 'b => writer('c), 'a) => writer('c) = + (m1, m2, x) => { + let (y, s1) = m1(x); + let (z, s2) = m2(y); + (z, StringLabels.concat(~sep="", [s1, s2])); + }; +}; diff --git a/src/content/1.8/code/reason/snippet18.re b/src/content/1.8/code/reason/snippet18.re new file mode 100644 index 000000000..211aab67b --- /dev/null +++ b/src/content/1.8/code/reason/snippet18.re @@ -0,0 +1,3 @@ +module KleisliIdentity = { + let return: 'a => writer('a) = a => (a, ""); +}; diff --git a/src/content/1.8/code/reason/snippet19.re b/src/content/1.8/code/reason/snippet19.re new file mode 100644 index 000000000..8b22f815c --- /dev/null +++ b/src/content/1.8/code/reason/snippet19.re @@ -0,0 +1,6 @@ +module KleisliFunctor: Functor = { + type t('a) = writer('a); + + let fmap = f => + KleisliComposition.(>=>)(id, x => KleisliIdentity.return(f(x))); +}; diff --git a/src/content/1.8/code/reason/snippet20.re b/src/content/1.8/code/reason/snippet20.re new file mode 100644 index 000000000..0bff8e254 --- /dev/null +++ b/src/content/1.8/code/reason/snippet20.re @@ -0,0 +1,3 @@ +module PartialArrow = (T: {type r;}) => { + type t('a) = T.r => 'a; +}; diff --git a/src/content/1.8/code/reason/snippet21.re b/src/content/1.8/code/reason/snippet21.re new file mode 100644 index 000000000..ba60a22c5 --- /dev/null +++ b/src/content/1.8/code/reason/snippet21.re @@ -0,0 +1 @@ +type reader('r, 'a) = 'r => 'a; diff --git a/src/content/1.8/code/reason/snippet22.re b/src/content/1.8/code/reason/snippet22.re new file mode 100644 index 000000000..f7bc7733c --- /dev/null +++ b/src/content/1.8/code/reason/snippet22.re @@ -0,0 +1,5 @@ +module ReaderFunctor = (In: {type r;}) : Functor => { + type t('a) = reader(In.r, 'a); + + let fmap = (f, g) => compose(f, g); +}; diff --git a/src/content/1.8/code/reason/snippet23.re b/src/content/1.8/code/reason/snippet23.re new file mode 100644 index 000000000..510872b9e --- /dev/null +++ b/src/content/1.8/code/reason/snippet23.re @@ -0,0 +1 @@ +type op('r, 'a) = 'a => 'r; diff --git a/src/content/1.8/code/reason/snippet24.re b/src/content/1.8/code/reason/snippet24.re new file mode 100644 index 000000000..698d28e07 --- /dev/null +++ b/src/content/1.8/code/reason/snippet24.re @@ -0,0 +1 @@ +let fmap: 'a, 'b . ('a => 'b) => ('a => 'r) => ('b => 'r) \ No newline at end of file diff --git a/src/content/1.8/code/reason/snippet25.re b/src/content/1.8/code/reason/snippet25.re new file mode 100644 index 000000000..fa4f05c41 --- /dev/null +++ b/src/content/1.8/code/reason/snippet25.re @@ -0,0 +1,5 @@ +module type Contravariant = { + type t('a); + + let contramap: ('b => 'a, t('a)) => t('b); +}; diff --git a/src/content/1.8/code/reason/snippet26.re b/src/content/1.8/code/reason/snippet26.re new file mode 100644 index 000000000..502856bea --- /dev/null +++ b/src/content/1.8/code/reason/snippet26.re @@ -0,0 +1,5 @@ +module OpContravariant = (In: {type r;}) : Contravariant => { + type t('a) = op(In.r, 'a); + + let contramap = (f, g) => compose(g, f); +}; diff --git a/src/content/1.8/code/reason/snippet27.re b/src/content/1.8/code/reason/snippet27.re new file mode 100644 index 000000000..8d891459c --- /dev/null +++ b/src/content/1.8/code/reason/snippet27.re @@ -0,0 +1 @@ +let flip = (f, b, a) => f(a, b); diff --git a/src/content/1.8/code/reason/snippet28.re b/src/content/1.8/code/reason/snippet28.re new file mode 100644 index 000000000..9d6644a57 --- /dev/null +++ b/src/content/1.8/code/reason/snippet28.re @@ -0,0 +1,3 @@ +let contramap: ('b => 'a, op('r, 'a)) => op('r, 'b) = ( + (f, g) => flip(compose, f, g): ('b => 'a, op('r, 'a)) => op('r, 'b) +); diff --git a/src/content/1.8/code/reason/snippet29.re b/src/content/1.8/code/reason/snippet29.re new file mode 100644 index 000000000..92112fbee --- /dev/null +++ b/src/content/1.8/code/reason/snippet29.re @@ -0,0 +1,29 @@ +/* Profunctor definition */ +module type Profunctor = { + type p('a, 'b); + + let dimap: ('a => 'b, 'c => 'd, p('b, 'c)) => p('a, 'd); +}; + +/* Profunctor alternate definition */ +module type ProfunctorExt = { + type p('a, 'b); + + let lmap: ('a => 'b, p('b, 'c)) => p('a, 'c); + let rmap: ('b => 'c, p('a, 'b)) => p('a, 'c); +}; + +/* Profunctor dimap defined using lmap and rmap */ +module Profunctor_Using_Ext = (PF: ProfunctorExt) : Profunctor => { + type p('a, 'b) = PF.p('a, 'b); + + let dimap = (f, g) => compose(PF.lmap(f), PF.rmap(g)); +}; + +/** Profunctor lmap and rmap defined using dimap */ +module ProfunctorExt_Using_Dimap = (PF: Profunctor) : ProfunctorExt => { + type p('a, 'b) = PF.p('a, 'b); + + let lmap = f => PF.dimap(f, id); + let rmap = g => PF.dimap(id, g); +}; diff --git a/src/content/1.8/code/reason/snippet30.re b/src/content/1.8/code/reason/snippet30.re new file mode 100644 index 000000000..f7fae62ed --- /dev/null +++ b/src/content/1.8/code/reason/snippet30.re @@ -0,0 +1,11 @@ +module ProfunctorArrow: Profunctor = { + type p('a, 'b) = 'a => 'b; + + let dimap = (f, g, p) => compose(g, compose(p, f)); +}; +module ProfunctorExtArrow: ProfunctorExt = { + type p('a, 'b) = 'a => 'b; + + let lmap = (f, p) => (flip(compose))(f, p); + let rmap = compose; +}; diff --git a/src/content/1.9/code/reason/snippet01.re b/src/content/1.9/code/reason/snippet01.re new file mode 100644 index 000000000..c566a4851 --- /dev/null +++ b/src/content/1.9/code/reason/snippet01.re @@ -0,0 +1 @@ +'a => ('b => 'c) diff --git a/src/content/1.9/code/reason/snippet02.re b/src/content/1.9/code/reason/snippet02.re new file mode 100644 index 000000000..4f13e8f3b --- /dev/null +++ b/src/content/1.9/code/reason/snippet02.re @@ -0,0 +1 @@ +'a => 'b => 'c diff --git a/src/content/1.9/code/reason/snippet03.re b/src/content/1.9/code/reason/snippet03.re new file mode 100644 index 000000000..59371b6be --- /dev/null +++ b/src/content/1.9/code/reason/snippet03.re @@ -0,0 +1 @@ +let catstr = (s, s') => String.concat(~sep="", [s, s']); diff --git a/src/content/1.9/code/reason/snippet04.re b/src/content/1.9/code/reason/snippet04.re new file mode 100644 index 000000000..59371b6be --- /dev/null +++ b/src/content/1.9/code/reason/snippet04.re @@ -0,0 +1 @@ +let catstr = (s, s') => String.concat(~sep="", [s, s']); diff --git a/src/content/1.9/code/reason/snippet05.re b/src/content/1.9/code/reason/snippet05.re new file mode 100644 index 000000000..1bb6e63bc --- /dev/null +++ b/src/content/1.9/code/reason/snippet05.re @@ -0,0 +1 @@ +let greet = catstr("Hello"); diff --git a/src/content/1.9/code/reason/snippet06.re b/src/content/1.9/code/reason/snippet06.re new file mode 100644 index 000000000..95e2b02bb --- /dev/null +++ b/src/content/1.9/code/reason/snippet06.re @@ -0,0 +1 @@ +('a, 'b) => 'a \ No newline at end of file diff --git a/src/content/1.9/code/reason/snippet07.re b/src/content/1.9/code/reason/snippet07.re new file mode 100644 index 000000000..cca9acd85 --- /dev/null +++ b/src/content/1.9/code/reason/snippet07.re @@ -0,0 +1 @@ +let curry = (f, a, b) => f((a, b)); diff --git a/src/content/1.9/code/reason/snippet08.re b/src/content/1.9/code/reason/snippet08.re new file mode 100644 index 000000000..1c1220dd1 --- /dev/null +++ b/src/content/1.9/code/reason/snippet08.re @@ -0,0 +1 @@ +let uncurry = (f, p) => f(fst(p), snd(p)); diff --git a/src/content/1.9/code/reason/snippet09.re b/src/content/1.9/code/reason/snippet09.re new file mode 100644 index 000000000..759ee9966 --- /dev/null +++ b/src/content/1.9/code/reason/snippet09.re @@ -0,0 +1 @@ +let factorizer = (g, a, b) => g((a, b)); diff --git a/src/content/1.9/code/reason/snippet10.re b/src/content/1.9/code/reason/snippet10.re new file mode 100644 index 000000000..efda49cc4 --- /dev/null +++ b/src/content/1.9/code/reason/snippet10.re @@ -0,0 +1,3 @@ +module type Exponential_Of_Sums_Example = { + let f: either(int, float) => string; +}; diff --git a/src/content/1.9/code/reason/snippet11.re b/src/content/1.9/code/reason/snippet11.re new file mode 100644 index 000000000..d3794b604 --- /dev/null +++ b/src/content/1.9/code/reason/snippet11.re @@ -0,0 +1,6 @@ +module Exp_Sum_Impl: Exponential_Of_Sums_Example = { + let f = + fun + | Left(n) => n < 0 ? "Negative int" : "Positive int" + | Right(x) => x < 0.0 ? "Negative double" : "Positive double" +}; diff --git a/src/content/1.9/code/reason/snippet12.re b/src/content/1.9/code/reason/snippet12.re new file mode 100644 index 000000000..147bf0956 --- /dev/null +++ b/src/content/1.9/code/reason/snippet12.re @@ -0,0 +1 @@ +let eval: (('a => 'b), 'a) => 'b \ No newline at end of file diff --git a/src/content/1.9/code/reason/snippet13.re b/src/content/1.9/code/reason/snippet13.re new file mode 100644 index 000000000..3c93ab4e7 --- /dev/null +++ b/src/content/1.9/code/reason/snippet13.re @@ -0,0 +1 @@ +let eval = ((f, a)) => f(a); diff --git a/src/content/1.9/code/reason/snippet14.re b/src/content/1.9/code/reason/snippet14.re new file mode 100644 index 000000000..f14576369 --- /dev/null +++ b/src/content/1.9/code/reason/snippet14.re @@ -0,0 +1 @@ +either('a, 'b) => 'a \ No newline at end of file diff --git a/src/content/1.9/code/reason/snippet15.re b/src/content/1.9/code/reason/snippet15.re new file mode 100644 index 000000000..587c3eaae --- /dev/null +++ b/src/content/1.9/code/reason/snippet15.re @@ -0,0 +1 @@ +let absurd: void => 'a \ No newline at end of file diff --git a/src/content/2.1/code/reason/snippet01.re b/src/content/2.1/code/reason/snippet01.re new file mode 100644 index 000000000..586f20875 --- /dev/null +++ b/src/content/2.1/code/reason/snippet01.re @@ -0,0 +1,2 @@ +/* Assume g and f are already defined */ +let h = compose(g, f); diff --git a/src/content/2.1/code/reason/snippet02.re b/src/content/2.1/code/reason/snippet02.re new file mode 100644 index 000000000..9e16ad80f --- /dev/null +++ b/src/content/2.1/code/reason/snippet02.re @@ -0,0 +1,4 @@ +let h = x => { + let y = f(x); + g(y); +}; diff --git a/src/content/2.2/code/reason/snippet01.re b/src/content/2.2/code/reason/snippet01.re new file mode 100644 index 000000000..dc0b67bce --- /dev/null +++ b/src/content/2.2/code/reason/snippet01.re @@ -0,0 +1,2 @@ +let p1 = compose(p, m); +let q1 = compose(q, m); diff --git a/src/content/2.2/code/reason/snippet02.re b/src/content/2.2/code/reason/snippet02.re new file mode 100644 index 000000000..a7a150770 --- /dev/null +++ b/src/content/2.2/code/reason/snippet02.re @@ -0,0 +1,4 @@ +let contramap: ('c_prime => 'c, 'c => 'limD, 'c_prime) => 'limD = ( + (f, u) => compose(u, f): + ('c_prime => 'c, 'c => 'limD, 'c_prime) => 'limD +); diff --git a/src/content/2.2/code/reason/snippet03.re b/src/content/2.2/code/reason/snippet03.re new file mode 100644 index 000000000..f4e5097a3 --- /dev/null +++ b/src/content/2.2/code/reason/snippet03.re @@ -0,0 +1,2 @@ +let f: 'a => 'b +let g: 'a => 'b diff --git a/src/content/2.2/code/reason/snippet04.re b/src/content/2.2/code/reason/snippet04.re new file mode 100644 index 000000000..f642988bf --- /dev/null +++ b/src/content/2.2/code/reason/snippet04.re @@ -0,0 +1,2 @@ +let p: 'c => 'a +let q: 'c => 'b diff --git a/src/content/2.2/code/reason/snippet05.re b/src/content/2.2/code/reason/snippet05.re new file mode 100644 index 000000000..cc15ba565 --- /dev/null +++ b/src/content/2.2/code/reason/snippet05.re @@ -0,0 +1,2 @@ +q == compose(f, p); +q == compose(g, p); diff --git a/src/content/2.2/code/reason/snippet06.re b/src/content/2.2/code/reason/snippet06.re new file mode 100644 index 000000000..36f01badc --- /dev/null +++ b/src/content/2.2/code/reason/snippet06.re @@ -0,0 +1,2 @@ +/* Pseudo ReasonML expressing function equality */ +compose(f, p) == compose(g, p); diff --git a/src/content/2.2/code/reason/snippet07.re b/src/content/2.2/code/reason/snippet07.re new file mode 100644 index 000000000..06eda04af --- /dev/null +++ b/src/content/2.2/code/reason/snippet07.re @@ -0,0 +1,2 @@ +let f = ((x, y)) => 2 * y + x; +let g = ((x, y)) => y - x; diff --git a/src/content/2.2/code/reason/snippet08.re b/src/content/2.2/code/reason/snippet08.re new file mode 100644 index 000000000..996c99e64 --- /dev/null +++ b/src/content/2.2/code/reason/snippet08.re @@ -0,0 +1 @@ +let p = t => (t, (-2) * t); diff --git a/src/content/2.2/code/reason/snippet09.re b/src/content/2.2/code/reason/snippet09.re new file mode 100644 index 000000000..1e4b6b8c6 --- /dev/null +++ b/src/content/2.2/code/reason/snippet09.re @@ -0,0 +1,2 @@ +/* Pseudo ReasonML expressing function equality */ +compose(f, p') == compose(g, p'); diff --git a/src/content/2.2/code/reason/snippet10.re b/src/content/2.2/code/reason/snippet10.re new file mode 100644 index 000000000..86d34f45e --- /dev/null +++ b/src/content/2.2/code/reason/snippet10.re @@ -0,0 +1 @@ +let p' = () => (0, 0); diff --git a/src/content/2.2/code/reason/snippet11.re b/src/content/2.2/code/reason/snippet11.re new file mode 100644 index 000000000..1aee74fe4 --- /dev/null +++ b/src/content/2.2/code/reason/snippet11.re @@ -0,0 +1 @@ +let p' = compose(p, h); diff --git a/src/content/2.2/code/reason/snippet12.re b/src/content/2.2/code/reason/snippet12.re new file mode 100644 index 000000000..16d641d89 --- /dev/null +++ b/src/content/2.2/code/reason/snippet12.re @@ -0,0 +1 @@ +let h = () => 0; diff --git a/src/content/2.2/code/reason/snippet13.re b/src/content/2.2/code/reason/snippet13.re new file mode 100644 index 000000000..ce5ec0f84 --- /dev/null +++ b/src/content/2.2/code/reason/snippet13.re @@ -0,0 +1,2 @@ +let f: 'a => 'b +let g: 'c => 'b diff --git a/src/content/2.2/code/reason/snippet14.re b/src/content/2.2/code/reason/snippet14.re new file mode 100644 index 000000000..137838661 --- /dev/null +++ b/src/content/2.2/code/reason/snippet14.re @@ -0,0 +1,3 @@ +let p: 'd => 'a +let q: 'd => 'c +let r: 'd => 'b diff --git a/src/content/2.2/code/reason/snippet15.re b/src/content/2.2/code/reason/snippet15.re new file mode 100644 index 000000000..3855420c0 --- /dev/null +++ b/src/content/2.2/code/reason/snippet15.re @@ -0,0 +1 @@ +compose(g, q) == compose(f, p); diff --git a/src/content/2.2/code/reason/snippet16.re b/src/content/2.2/code/reason/snippet16.re new file mode 100644 index 000000000..d92c3bd55 --- /dev/null +++ b/src/content/2.2/code/reason/snippet16.re @@ -0,0 +1 @@ +let f = x => 1.23; diff --git a/src/content/2.2/code/reason/snippet17.re b/src/content/2.2/code/reason/snippet17.re new file mode 100644 index 000000000..e9d9f9249 --- /dev/null +++ b/src/content/2.2/code/reason/snippet17.re @@ -0,0 +1,13 @@ +module type Contravariant = { + type t('a); + let contramap: ('b => 'a, t('a)) => t('b); +}; + +type tostring('a) = + | ToString('a => string); + +module ToStringInstance: Contravariant = { + type t('a) = tostring('a); + + let contramap = (f, ToString(g)) => ToString(compose(g, f)); +}; diff --git a/src/content/2.2/code/reason/snippet18.re b/src/content/2.2/code/reason/snippet18.re new file mode 100644 index 000000000..1757e48f0 --- /dev/null +++ b/src/content/2.2/code/reason/snippet18.re @@ -0,0 +1 @@ +toString((either('b, 'c))) ~ (b => string, c => string) \ No newline at end of file diff --git a/src/content/2.2/code/reason/snippet19.re b/src/content/2.2/code/reason/snippet19.re new file mode 100644 index 000000000..6e4bbb442 --- /dev/null +++ b/src/content/2.2/code/reason/snippet19.re @@ -0,0 +1 @@ +'r => ('a, 'b) ~ ('r => 'a, 'r => 'b) \ No newline at end of file diff --git a/src/content/2.3/code/reason/snippet01.re b/src/content/2.3/code/reason/snippet01.re new file mode 100644 index 000000000..5b98f2ca1 --- /dev/null +++ b/src/content/2.3/code/reason/snippet01.re @@ -0,0 +1,6 @@ +module type Monoid = { + type m; + + let mempty: m; + let mappend: (m, m) => m; +}; diff --git a/src/content/2.3/code/reason/snippet02.re b/src/content/2.3/code/reason/snippet02.re new file mode 100644 index 000000000..12c554687 --- /dev/null +++ b/src/content/2.3/code/reason/snippet02.re @@ -0,0 +1,7 @@ +module ListMonoid = (T1: {type a;}) : + (Monoid with type m = list(T1.a)) => { + type m = list(T1.a); + + let mempty = []; + let mappend = (xs, ys) => List.append(xs, ys); +}; diff --git a/src/content/2.3/code/reason/snippet03.re b/src/content/2.3/code/reason/snippet03.re new file mode 100644 index 000000000..7f4d09afd --- /dev/null +++ b/src/content/2.3/code/reason/snippet03.re @@ -0,0 +1,2 @@ +2 * 3 == 6 +List.append([2], [3]) == [2, 3]; diff --git a/src/content/2.3/code/reason/snippet04.re b/src/content/2.3/code/reason/snippet04.re new file mode 100644 index 000000000..6e4b66e06 --- /dev/null +++ b/src/content/2.3/code/reason/snippet04.re @@ -0,0 +1 @@ +let h (a * b) = h a * h b \ No newline at end of file diff --git a/src/content/2.3/code/reason/snippet05.re b/src/content/2.3/code/reason/snippet05.re new file mode 100644 index 000000000..09d1fabae --- /dev/null +++ b/src/content/2.3/code/reason/snippet05.re @@ -0,0 +1 @@ +List.append([2], [3]) == [2, 3]; diff --git a/src/content/2.3/code/reason/snippet06.re b/src/content/2.3/code/reason/snippet06.re new file mode 100644 index 000000000..7e038343f --- /dev/null +++ b/src/content/2.3/code/reason/snippet06.re @@ -0,0 +1 @@ +2 * 3 == 6; diff --git a/src/content/2.3/code/reason/snippet07.re b/src/content/2.3/code/reason/snippet07.re new file mode 100644 index 000000000..a743faa26 --- /dev/null +++ b/src/content/2.3/code/reason/snippet07.re @@ -0,0 +1,6 @@ +module type FreeMonoidRep = (F: Functor) => { + type x; + type m; + + let p: x => F.t(m); +}; diff --git a/src/content/2.3/code/reason/snippet08.re b/src/content/2.3/code/reason/snippet08.re new file mode 100644 index 000000000..e72b2b798 --- /dev/null +++ b/src/content/2.3/code/reason/snippet08.re @@ -0,0 +1,6 @@ +module type FreeMonoidRep = (F: Functor) => { + type x; + type n; + + let q: x => F.t(n); +}; diff --git a/src/content/2.3/code/reason/snippet09.re b/src/content/2.3/code/reason/snippet09.re new file mode 100644 index 000000000..ecc12fefc --- /dev/null +++ b/src/content/2.3/code/reason/snippet09.re @@ -0,0 +1 @@ +let h: m => n diff --git a/src/content/2.3/code/reason/snippet10.re b/src/content/2.3/code/reason/snippet10.re new file mode 100644 index 000000000..3d4d1ce06 --- /dev/null +++ b/src/content/2.3/code/reason/snippet10.re @@ -0,0 +1 @@ +let q: compose(uh p) diff --git a/src/content/2.4/code/reason/snippet01.re b/src/content/2.4/code/reason/snippet01.re new file mode 100644 index 000000000..e9602455f --- /dev/null +++ b/src/content/2.4/code/reason/snippet01.re @@ -0,0 +1 @@ +type reader('a, 'x) = 'a => 'x; diff --git a/src/content/2.4/code/reason/snippet02.re b/src/content/2.4/code/reason/snippet02.re new file mode 100644 index 000000000..c946134fa --- /dev/null +++ b/src/content/2.4/code/reason/snippet02.re @@ -0,0 +1,5 @@ +module ReaderFunctor = (T: {type r;}) : Functor => { + type t('a) = reader(T.r, 'a); + + let fmap = (f, h, a) => f(h(a)); +}; diff --git a/src/content/2.4/code/reason/snippet03.re b/src/content/2.4/code/reason/snippet03.re new file mode 100644 index 000000000..469445203 --- /dev/null +++ b/src/content/2.4/code/reason/snippet03.re @@ -0,0 +1 @@ +type op('a, 'x) = 'x => 'a; diff --git a/src/content/2.4/code/reason/snippet04.re b/src/content/2.4/code/reason/snippet04.re new file mode 100644 index 000000000..7d3df5641 --- /dev/null +++ b/src/content/2.4/code/reason/snippet04.re @@ -0,0 +1,5 @@ +module OpContravariant = (T: {type r;}) : Contravariant => { + type t('a) = op(T.r, 'a); + + let contramap = (f, h, b) => h(f(b)); +}; diff --git a/src/content/2.4/code/reason/snippet05.re b/src/content/2.4/code/reason/snippet05.re new file mode 100644 index 000000000..5e49e68b5 --- /dev/null +++ b/src/content/2.4/code/reason/snippet05.re @@ -0,0 +1,7 @@ +module ProfunctorArrow: Profunctor = { + type p('a, 'b) = 'a => 'b; + + let dimap = (f, g, p) => compose(g, compose(p, f)); + let lmap = (f, p) => (flip(compose))(f, p); + let rmap = compose; +}; diff --git a/src/content/2.4/code/reason/snippet06.re b/src/content/2.4/code/reason/snippet06.re new file mode 100644 index 000000000..13dd79567 --- /dev/null +++ b/src/content/2.4/code/reason/snippet06.re @@ -0,0 +1,6 @@ +module type NT_AX_FX = { + type a; + type t('x); + + let alpha: (a => 'x) => t('x); +}; diff --git a/src/content/2.4/code/reason/snippet07.re b/src/content/2.4/code/reason/snippet07.re new file mode 100644 index 000000000..939c16366 --- /dev/null +++ b/src/content/2.4/code/reason/snippet07.re @@ -0,0 +1 @@ +compose(F.fmap(f), NT.alpha) == compose(NT.alpha, F.fmap(f)); diff --git a/src/content/2.4/code/reason/snippet08.re b/src/content/2.4/code/reason/snippet08.re new file mode 100644 index 000000000..d848bacd9 --- /dev/null +++ b/src/content/2.4/code/reason/snippet08.re @@ -0,0 +1 @@ +F.fmap(f, N.alpha(h)) == N.alpha(compose(f, h)); diff --git a/src/content/2.4/code/reason/snippet09.re b/src/content/2.4/code/reason/snippet09.re new file mode 100644 index 000000000..be7c68c78 --- /dev/null +++ b/src/content/2.4/code/reason/snippet09.re @@ -0,0 +1,6 @@ +module type NT_FX_AX = { + type a; + type t('x); + + let beta: (t('x), a) => 'x; +}; diff --git a/src/content/2.4/code/reason/snippet10.re b/src/content/2.4/code/reason/snippet10.re new file mode 100644 index 000000000..d32eebd89 --- /dev/null +++ b/src/content/2.4/code/reason/snippet10.re @@ -0,0 +1,7 @@ +module NT_Impl = (F: Functor with type t('a) = list('a)): + (NT_AX_FX with type a = int and type t('x) = list('x)) => { + type a = int; + type t('x) = list('x); + + let alpha: 'x . (int => 'x) => list('x) = h => F.fmap(h, [12]); +}; diff --git a/src/content/2.4/code/reason/snippet11.re b/src/content/2.4/code/reason/snippet11.re new file mode 100644 index 000000000..649c422aa --- /dev/null +++ b/src/content/2.4/code/reason/snippet11.re @@ -0,0 +1 @@ +F.fmap(f, F.fmap(h, [12])) == F.fmap(compose(f, h), [12]); diff --git a/src/content/2.4/code/reason/snippet12.re b/src/content/2.4/code/reason/snippet12.re new file mode 100644 index 000000000..8122a2def --- /dev/null +++ b/src/content/2.4/code/reason/snippet12.re @@ -0,0 +1,6 @@ +module type NT_ListX_IntX = { + type a = int; + type t('x) = list('x); + + let beta: (t('x), a) => 'x; +}; diff --git a/src/content/2.4/code/reason/snippet13.re b/src/content/2.4/code/reason/snippet13.re new file mode 100644 index 000000000..399920573 --- /dev/null +++ b/src/content/2.4/code/reason/snippet13.re @@ -0,0 +1,7 @@ +module type Representable = { + type t('x); + type rep; /* Representing type 'a' */ + + let tabulate: (rep => 'x) => t('x); + let index: (t('x), rep) => 'x; +}; diff --git a/src/content/2.4/code/reason/snippet14.re b/src/content/2.4/code/reason/snippet14.re new file mode 100644 index 000000000..aec142ec7 --- /dev/null +++ b/src/content/2.4/code/reason/snippet14.re @@ -0,0 +1,2 @@ +type stream('a) = + | Cons('a, Lazy.t(stream('a))); diff --git a/src/content/2.4/code/reason/snippet15.re b/src/content/2.4/code/reason/snippet15.re new file mode 100644 index 000000000..962528377 --- /dev/null +++ b/src/content/2.4/code/reason/snippet15.re @@ -0,0 +1,9 @@ +module StreamRepresentable: Representable = { + type rep = int; + type t('x) = stream('x); + + let rec tabulate = f => Cons(f(0), lazy(tabulate(compose(f, succ)))); + + let rec index = (Cons(b, bs), n) => + n == 0 ? b : index(Lazy.force(bs), n - 1); +}; diff --git a/src/content/2.5/code/reason/snippet01.re b/src/content/2.5/code/reason/snippet01.re new file mode 100644 index 000000000..e9602455f --- /dev/null +++ b/src/content/2.5/code/reason/snippet01.re @@ -0,0 +1 @@ +type reader('a, 'x) = 'a => 'x; diff --git a/src/content/2.5/code/reason/snippet02.re b/src/content/2.5/code/reason/snippet02.re new file mode 100644 index 000000000..e928907dc --- /dev/null +++ b/src/content/2.5/code/reason/snippet02.re @@ -0,0 +1,7 @@ +module ReaderFunctor = (T: {type a;}) : Functor => { + type t('x) = reader(T.a, 'x); + + let fmap: ('x => 'y, t('x)) => t('y) = ( + (f, r, a) => f(r(a)): ('x => 'y, t('x)) => t('y) + ); +}; diff --git a/src/content/2.5/code/reason/snippet03.re b/src/content/2.5/code/reason/snippet03.re new file mode 100644 index 000000000..13dd79567 --- /dev/null +++ b/src/content/2.5/code/reason/snippet03.re @@ -0,0 +1,6 @@ +module type NT_AX_FX = { + type a; + type t('x); + + let alpha: (a => 'x) => t('x); +}; diff --git a/src/content/2.5/code/reason/snippet04.re b/src/content/2.5/code/reason/snippet04.re new file mode 100644 index 000000000..ddbb43df6 --- /dev/null +++ b/src/content/2.5/code/reason/snippet04.re @@ -0,0 +1 @@ +let alpha: (a => 'x) => t('x) diff --git a/src/content/2.5/code/reason/snippet05.re b/src/content/2.5/code/reason/snippet05.re new file mode 100644 index 000000000..f9456ff78 --- /dev/null +++ b/src/content/2.5/code/reason/snippet05.re @@ -0,0 +1 @@ +alpha(id) : f('a) \ No newline at end of file diff --git a/src/content/2.5/code/reason/snippet06.re b/src/content/2.5/code/reason/snippet06.re new file mode 100644 index 000000000..2dd3f1b58 --- /dev/null +++ b/src/content/2.5/code/reason/snippet06.re @@ -0,0 +1 @@ +let fa: f('a) diff --git a/src/content/2.5/code/reason/snippet07.re b/src/content/2.5/code/reason/snippet07.re new file mode 100644 index 000000000..b5a9ec78a --- /dev/null +++ b/src/content/2.5/code/reason/snippet07.re @@ -0,0 +1 @@ +alpha(h) == F.fmap(h, fa); diff --git a/src/content/2.6/code/reason/snippet01.re b/src/content/2.6/code/reason/snippet01.re new file mode 100644 index 000000000..947a82dc3 --- /dev/null +++ b/src/content/2.6/code/reason/snippet01.re @@ -0,0 +1,11 @@ +module type BtoA = { + type a; + type b; + + let btoa: b => a; +}; + +/* Define the Yoneda embedding */ +module Yoneda_Embedding = (E: BtoA) => { + let fromY: 'x. (E.a => 'x, E.b) => 'x = (f, b) => f(E.btoa(b)); +}; diff --git a/src/content/2.6/code/reason/snippet02.re b/src/content/2.6/code/reason/snippet02.re new file mode 100644 index 000000000..b13dd73b0 --- /dev/null +++ b/src/content/2.6/code/reason/snippet02.re @@ -0,0 +1,2 @@ +module YE = Yoneda_Embedding(BtoAImpl); +YE.fromY(id) /* output type : BtoA.b => BtoA.a */ diff --git a/src/content/3.10/code/reason/snippet01.re b/src/content/3.10/code/reason/snippet01.re new file mode 100644 index 000000000..002888d9d --- /dev/null +++ b/src/content/3.10/code/reason/snippet01.re @@ -0,0 +1,13 @@ +module type Functor = { + type t('a); + + let fmap: ('a => 'b, t('a)) => t('b); +}; + +module type Profunctor = { + type p('a, 'b); + + let dimap: ('c => 'a, 'b => 'd, p('a, 'b)) => p('c, 'd); +}; + +let id = a => a; diff --git a/src/content/3.10/code/reason/snippet02.re b/src/content/3.10/code/reason/snippet02.re new file mode 100644 index 000000000..458c53499 --- /dev/null +++ b/src/content/3.10/code/reason/snippet02.re @@ -0,0 +1 @@ +let dimap(f, id, (P (b, b))) : p('a, 'b); \ No newline at end of file diff --git a/src/content/3.10/code/reason/snippet03.re b/src/content/3.10/code/reason/snippet03.re new file mode 100644 index 000000000..10fc7b3ea --- /dev/null +++ b/src/content/3.10/code/reason/snippet03.re @@ -0,0 +1 @@ +let dimap(id, f, (P (a, a))) : p('a, 'b); \ No newline at end of file diff --git a/src/content/3.10/code/reason/snippet04.re b/src/content/3.10/code/reason/snippet04.re new file mode 100644 index 000000000..05d805594 --- /dev/null +++ b/src/content/3.10/code/reason/snippet04.re @@ -0,0 +1,2 @@ +/* There is no compose operator in ReasonML */ +compose(dimap(id, f), alpha) == compose(dimap(f, id), alpha); diff --git a/src/content/3.10/code/reason/snippet05.re b/src/content/3.10/code/reason/snippet05.re new file mode 100644 index 000000000..9d36a9ece --- /dev/null +++ b/src/content/3.10/code/reason/snippet05.re @@ -0,0 +1 @@ +'a. p('a, 'a); \ No newline at end of file diff --git a/src/content/3.10/code/reason/snippet06.re b/src/content/3.10/code/reason/snippet06.re new file mode 100644 index 000000000..4d9dcd1f1 --- /dev/null +++ b/src/content/3.10/code/reason/snippet06.re @@ -0,0 +1 @@ +compose(dimap(f, id), pi) == compose(dimap(id, f), pi); diff --git a/src/content/3.10/code/reason/snippet07.re b/src/content/3.10/code/reason/snippet07.re new file mode 100644 index 000000000..3c410731a --- /dev/null +++ b/src/content/3.10/code/reason/snippet07.re @@ -0,0 +1,5 @@ +module type Polymorphic_Projection = (P: Profunctor) => { + type rank2_p = {p: 'c. P.p('c, 'c)}; + + let pi: rank2_p => P.p('a, 'b); +}; diff --git a/src/content/3.10/code/reason/snippet08.re b/src/content/3.10/code/reason/snippet08.re new file mode 100644 index 000000000..a11e6d282 --- /dev/null +++ b/src/content/3.10/code/reason/snippet08.re @@ -0,0 +1,5 @@ +module Pi = (P: Profunctor) => { + type rank2_p = {p: 'a. P.p('a, 'a)}; + + let pi: rank2_p => P.p('c, 'c) = (e => e.p: rank2_p => P.p('c, 'c)); +}; diff --git a/src/content/3.10/code/reason/snippet09.re b/src/content/3.10/code/reason/snippet09.re new file mode 100644 index 000000000..3afb3b626 --- /dev/null +++ b/src/content/3.10/code/reason/snippet09.re @@ -0,0 +1,9 @@ +module EndsEqualizer = (P: Profunctor) => { + let lambda: (P.p('a, 'a), 'a => 'b) => P.p('a, 'b) = ( + (paa, f) => P.dimap(id, f, paa) + ); + + let rho: (P.p('b, 'b), 'a => 'b) => P.p('a, 'b) = ( + (pbb, f) => P.dimap(f, id, pbb) + ); +}; diff --git a/src/content/3.10/code/reason/snippet10.re b/src/content/3.10/code/reason/snippet10.re new file mode 100644 index 000000000..ba06dd492 --- /dev/null +++ b/src/content/3.10/code/reason/snippet10.re @@ -0,0 +1,4 @@ +module type ProdP = { + type p('a, 'b); + type prod_p('a, 'b) = ('a => 'b) => p('a, 'b); +}; diff --git a/src/content/3.10/code/reason/snippet11.re b/src/content/3.10/code/reason/snippet11.re new file mode 100644 index 000000000..62bffb248 --- /dev/null +++ b/src/content/3.10/code/reason/snippet11.re @@ -0,0 +1,5 @@ +module type DiaProd = { + type p('a, 'b); + type diaprod('a) = + | DiaProd(p('a, 'a)); +}; diff --git a/src/content/3.10/code/reason/snippet12.re b/src/content/3.10/code/reason/snippet12.re new file mode 100644 index 000000000..12a1280f8 --- /dev/null +++ b/src/content/3.10/code/reason/snippet12.re @@ -0,0 +1,15 @@ +module EndsWithDiaProd = ( + P: Profunctor, + D: DiaProd with type p('a, 'b) = P.p('a, 'b), + PP: ProdP with type p('a, 'b) = P.p('a, 'b), + ) => { + module E = EndsEqualizer(P); + + let lambdaP: D.diaprod('a) => PP.prod_p('a, 'b) = ( + (DiaProd(paa)) => E.lambda(paa) + ); + + let rhoP: D.diaprod('b) => PP.prod_p('a, 'b) = ( + (DiaProd(pbb)) => E.rho(pbb) + ); +}; diff --git a/src/content/3.10/code/reason/snippet13.re b/src/content/3.10/code/reason/snippet13.re new file mode 100644 index 000000000..d2f924321 --- /dev/null +++ b/src/content/3.10/code/reason/snippet13.re @@ -0,0 +1,4 @@ +/* Higher rank types can be introduced via records */ +module NT_as_Ends = (F: Functor, G: Functor) => { + type set_of_nt = {nt: 'a. F.t('a) => G.t('a)}; +}; diff --git a/src/content/3.10/code/reason/snippet14.re b/src/content/3.10/code/reason/snippet14.re new file mode 100644 index 000000000..72ac410fd --- /dev/null +++ b/src/content/3.10/code/reason/snippet14.re @@ -0,0 +1,4 @@ +module Coend = (P: Profunctor) => { + type coend = + | Coend({c: 'a. P.p('a, 'a)}); +}; diff --git a/src/content/3.10/code/reason/snippet15.re b/src/content/3.10/code/reason/snippet15.re new file mode 100644 index 000000000..a3cbdd674 --- /dev/null +++ b/src/content/3.10/code/reason/snippet15.re @@ -0,0 +1,8 @@ +module type SumP = { + type a; + type b; + type p('a, 'b); + + let f: b => a; + let pab: p(a, b); +}; diff --git a/src/content/3.10/code/reason/snippet16.re b/src/content/3.10/code/reason/snippet16.re new file mode 100644 index 000000000..6e5ac250e --- /dev/null +++ b/src/content/3.10/code/reason/snippet16.re @@ -0,0 +1,31 @@ +module type DiagSum = { + type a; + type p('a, 'b); + + let paa: p(a, a); +}; + +module CoEndImpl = (P: Profunctor) => { + type a; + type b; + + module type Sum_P = + SumP with type p('a, 'b) = P.p('a, 'b) + and type a = a and type b = b; + + let lambda = (module S: Sum_P): (module DiagSum) => + (module { + type a = S.b; + type p('a, 'b) = P.p('a, 'b); + + let paa = P.dimap(S.f, id, S.pab); + }); + + let rho = (module S: Sum_P): (module DiagSum) => + (module { + type a = S.a; + type p('a, 'b) = P.p('a, 'b); + + let paa = P.dimap(id, S.f, S.pab); + }); +}; diff --git a/src/content/3.10/code/reason/snippet17.re b/src/content/3.10/code/reason/snippet17.re new file mode 100644 index 000000000..27c9f7aa0 --- /dev/null +++ b/src/content/3.10/code/reason/snippet17.re @@ -0,0 +1,6 @@ +module type DiagSum = { + type a; + type p('a, 'b); + + let paa: p(a, a); +}; diff --git a/src/content/3.10/code/reason/snippet18.re b/src/content/3.10/code/reason/snippet18.re new file mode 100644 index 000000000..a4b494183 --- /dev/null +++ b/src/content/3.10/code/reason/snippet18.re @@ -0,0 +1,7 @@ +module type Procompose = { + type p('a, 'b); + type q('a, 'b); + + type procompose(_, _) = + | Procompose(q('a, 'c) => p('c, 'b)): procompose('a, 'b); +}; diff --git a/src/content/3.11/code/reason/snippet01.re b/src/content/3.11/code/reason/snippet01.re new file mode 100644 index 000000000..f1c920279 --- /dev/null +++ b/src/content/3.11/code/reason/snippet01.re @@ -0,0 +1,6 @@ +module type Ran = { + type k('a); + type d('a); + type ran('a) = + | Ran({r: 'i. ('a => k('i)) => d('i)}); +}; diff --git a/src/content/3.11/code/reason/snippet02.re b/src/content/3.11/code/reason/snippet02.re new file mode 100644 index 000000000..03fc51aa7 --- /dev/null +++ b/src/content/3.11/code/reason/snippet02.re @@ -0,0 +1 @@ +let f: string => tree(int); diff --git a/src/content/3.11/code/reason/snippet03.re b/src/content/3.11/code/reason/snippet03.re new file mode 100644 index 000000000..d31bfa117 --- /dev/null +++ b/src/content/3.11/code/reason/snippet03.re @@ -0,0 +1,2 @@ +/* Higher rank polymorphic functions can be achieved using records */ +{ r : 'i. (a => k('i)) => 'i } diff --git a/src/content/3.11/code/reason/snippet04.re b/src/content/3.11/code/reason/snippet04.re new file mode 100644 index 000000000..5dc1b6b47 --- /dev/null +++ b/src/content/3.11/code/reason/snippet04.re @@ -0,0 +1,10 @@ +module type Lst = { + type a; + type m; + + module M: Monoid with type m = m; + + type lst = (a => M.m) => M.m; + + let f: lst; +}; diff --git a/src/content/3.11/code/reason/snippet05.re b/src/content/3.11/code/reason/snippet05.re new file mode 100644 index 000000000..06fe9ac44 --- /dev/null +++ b/src/content/3.11/code/reason/snippet05.re @@ -0,0 +1,22 @@ +let fold_map = (type i, module M: Monoid with type m = i, xs, f) => + List.fold_left((acc, a) => M.mappend(acc, f(a)), M.mempty, xs); + +let to_lst = (type x, xs: list(x)) => { + module LM: Monoid with type m = list(x) = + ListMonoid({type a = x;}); + + (module { + type a = x; + type m = list(x); + + module M = LM; + + type lst = (a => LM.m) => LM.m; + + let f = g => fold_map((module LM), xs, g); + }); +}; + +let from_lst = (type x, + module LstImpl: Lst with type a = x and type m = list(x) + ) => LstImpl.f(x => [x]); diff --git a/src/content/3.11/code/reason/snippet06.re b/src/content/3.11/code/reason/snippet06.re new file mode 100644 index 000000000..c5291c484 --- /dev/null +++ b/src/content/3.11/code/reason/snippet06.re @@ -0,0 +1,9 @@ +module type Lan = { + type k('a); + type d('a); + type a; + type i; + + let fk: k(i) => a; + let di: d(i); +}; diff --git a/src/content/3.11/code/reason/snippet07.re b/src/content/3.11/code/reason/snippet07.re new file mode 100644 index 000000000..ab90f3046 --- /dev/null +++ b/src/content/3.11/code/reason/snippet07.re @@ -0,0 +1,12 @@ +module type Exp = { + type a; + type b; + type d('a) = + | I('a); + type k('a) = ('a, a); + + include + Lan with type k('a) := (a, 'a) + and type d('a) := d('a) + and type a := b; +}; diff --git a/src/content/3.11/code/reason/snippet08.re b/src/content/3.11/code/reason/snippet08.re new file mode 100644 index 000000000..77ad9d4f8 --- /dev/null +++ b/src/content/3.11/code/reason/snippet08.re @@ -0,0 +1,19 @@ +let to_exp = (type a', type b', f) : + (module Exp with type a = a' and type b = b') => + (module { + type a = a'; + type b = b'; + type d('a) = + | I('a); + type k('a) = ('a, a); + type i = unit; + + let fk = ((a, _)) => f(a); + let di = I(); + }); + +let from_exp = (type a', type b', + module E: Exp with type a = a' and type b = b', a) => { + let I(i) = E.di; + E.fk((a, i)); +}; diff --git a/src/content/3.11/code/reason/snippet09.re b/src/content/3.11/code/reason/snippet09.re new file mode 100644 index 000000000..aa187852c --- /dev/null +++ b/src/content/3.11/code/reason/snippet09.re @@ -0,0 +1,8 @@ +module type FreeF = { + type f('a); + type a; + type i; + + let h: i => a; + let fi: i => f(i); +}; diff --git a/src/content/3.11/code/reason/snippet10.re b/src/content/3.11/code/reason/snippet10.re new file mode 100644 index 000000000..66ad80a8d --- /dev/null +++ b/src/content/3.11/code/reason/snippet10.re @@ -0,0 +1,18 @@ +module FreeFunctor = (F: {type f('a);}) : Functor => { + module type F = FreeF with type f('a) = F.f('a); + + type t('a) = (module F with type a = 'a); + + let fmap = + (type a', type b', + f: a' => b', module FF: F with type a = a') : + (module F with type a = b') => + (module { + type f('a) = F.f('a); + type a = b'; + type i = FF.i; + + let h = i => f(FF.h(i)); + let fi = FF.fi; + }); +}; diff --git a/src/content/3.11/code/reason/snippet11.re b/src/content/3.11/code/reason/snippet11.re new file mode 100644 index 000000000..d2405401f --- /dev/null +++ b/src/content/3.11/code/reason/snippet11.re @@ -0,0 +1,6 @@ +module type FreeF_Alt = { + type a; + type f('a); + + let freeF: (a => 'i) => f('i); +}; diff --git a/src/content/3.11/code/reason/snippet12.re b/src/content/3.11/code/reason/snippet12.re new file mode 100644 index 000000000..97c9ff13c --- /dev/null +++ b/src/content/3.11/code/reason/snippet12.re @@ -0,0 +1,15 @@ +module FreeFunctorAlt = (F: {type f('a);}) : Functor => { + module type F = FreeF_Alt with type f('a) = F.f('a); + + type t('a) = (module F with type a = 'a); + + let fmap = + (type a', type b', f, module FF: F with type a = a') + : (module F with type a = b') => + (module { + type a = b'; + type f('a) = F.f('a); + + let freeF = bi => FF.freeF(a => bi(f(a))); + }); +}; diff --git a/src/content/3.14/code/reason/snippet01.re b/src/content/3.14/code/reason/snippet01.re new file mode 100644 index 000000000..535ba9ab9 --- /dev/null +++ b/src/content/3.14/code/reason/snippet01.re @@ -0,0 +1,5 @@ +type either('a, 'b) = + | Left('a) + | Right('b); + +type two = either(unit, unit); diff --git a/src/content/3.14/code/reason/snippet02.re b/src/content/3.14/code/reason/snippet02.re new file mode 100644 index 000000000..3bf68757c --- /dev/null +++ b/src/content/3.14/code/reason/snippet02.re @@ -0,0 +1 @@ +let raise: unit => 'a; diff --git a/src/content/3.14/code/reason/snippet03.re b/src/content/3.14/code/reason/snippet03.re new file mode 100644 index 000000000..6c58dcde5 --- /dev/null +++ b/src/content/3.14/code/reason/snippet03.re @@ -0,0 +1 @@ +type option('a) = either(unit, 'a); diff --git a/src/content/3.14/code/reason/snippet04.re b/src/content/3.14/code/reason/snippet04.re new file mode 100644 index 000000000..78fde77e7 --- /dev/null +++ b/src/content/3.14/code/reason/snippet04.re @@ -0,0 +1,3 @@ +type option('a) = + | None + | Some('a); diff --git a/src/content/3.2/code/reason/snippet01.re b/src/content/3.2/code/reason/snippet01.re new file mode 100644 index 000000000..ebf43ff0b --- /dev/null +++ b/src/content/3.2/code/reason/snippet01.re @@ -0,0 +1 @@ +let swap = (a, b) => (b, a); diff --git a/src/content/3.2/code/reason/snippet02.re b/src/content/3.2/code/reason/snippet02.re new file mode 100644 index 000000000..7d9bc42ab --- /dev/null +++ b/src/content/3.2/code/reason/snippet02.re @@ -0,0 +1,5 @@ +module type Unit_Example = { + type m('a); + + let return: 'd => m('d); +}; diff --git a/src/content/3.2/code/reason/snippet03.re b/src/content/3.2/code/reason/snippet03.re new file mode 100644 index 000000000..95a6f73fb --- /dev/null +++ b/src/content/3.2/code/reason/snippet03.re @@ -0,0 +1,5 @@ +module type Counit_Example = { + type w('c); + + let extract: w('c) => 'c; +}; diff --git a/src/content/3.2/code/reason/snippet04.re b/src/content/3.2/code/reason/snippet04.re new file mode 100644 index 000000000..3b94e22e8 --- /dev/null +++ b/src/content/3.2/code/reason/snippet04.re @@ -0,0 +1,6 @@ +/* L is Functor F and R is Representable Functor U */ +module type Adjunction = + (F: Functor, U: Representable) => { + let unit: 'a => U.t(F.t('a)); + let counit: F.t(U.t('a)) => 'a; + }; diff --git a/src/content/3.2/code/reason/snippet05.re b/src/content/3.2/code/reason/snippet05.re new file mode 100644 index 000000000..1c74c50e8 --- /dev/null +++ b/src/content/3.2/code/reason/snippet05.re @@ -0,0 +1,5 @@ +module type Adjunction_HomSet = + (F: Functor, U: Representable) => { + let left_adjunct: (F.t('a) => 'b, 'a) => U.t('b); + let right_adjunct: ('a => U.t('b), F.t('a)) => 'b; + }; diff --git a/src/content/3.2/code/reason/snippet06.re b/src/content/3.2/code/reason/snippet06.re new file mode 100644 index 000000000..f4dee8512 --- /dev/null +++ b/src/content/3.2/code/reason/snippet06.re @@ -0,0 +1,49 @@ +/* Putting it all together to show the equivalence between +* unit & counit and left_adjunct & right_adjunct */ +module type Adjunction = + (F: Functor, U: Representable) => { + let unit: 'a => U.t(F.t('a)); + let counit: F.t(U.t('a)) => 'a; + let left_adjunct: (F.t('a) => 'b, 'a) => U.t('b); + let right_adjunct: ('a => U.t('b), F.t('a)) => 'b; + }; + +/* Adjunction via unit & counit */ +module type Adjunction_Unit_Counit = + (F: Functor, U: Representable) => { + let unit: 'a => U.t(F.t('a)); + let counit: F.t(U.t('a)) => 'a; + }; + +/* Adjunction via left and right adjoints */ +module type Adjunction_Hom_Set = + (F: Functor, U: Representable) => { + let left_adjunct: (F.t('a) => 'b, 'a) => U.t('b); + let right_adjunct: ('a => U.t('b), F.t('a)) => 'b; + }; + +/* Implementing unit & counit from left and right adjoint definitions */ +module Adjunction_From_Hom_Set = (A: Adjunction_Hom_Set) : Adjunction => + (F: Functor, U: Representable) => { + type f('t) = F.t('t); + type u('t) = U.t('t); + + module M = A(F, U); + include M; + + let unit: 'a. 'a => u(f('a)) = a => M.left_adjunct(idty, a); + let counit: 'a. f(u('a)) => 'a = fua => M.right_adjunct(idty, fua); + }; + +/* Implementing left and right adjunct from unit & counit Definitions */ +module Adjunction_From_Unit_Counit = (A: Adjunction_Unit_Counit) : Adjunction => + (F: Functor, U: Representable) => { + type f('t) = F.t('t); + type u('t) = U.t('t); + + module M = A(F, U); + include M; + + let left_adjunct = (f, a) => (U.fmap(f))(M.unit(a)); + let right_adjunct = (f, fa) => M.counit(F.fmap(f, fa)); + }; diff --git a/src/content/3.2/code/reason/snippet07.re b/src/content/3.2/code/reason/snippet07.re new file mode 100644 index 000000000..fcc485733 --- /dev/null +++ b/src/content/3.2/code/reason/snippet07.re @@ -0,0 +1 @@ +let factorizer = (p, q, x) => (p(x), q(x)); diff --git a/src/content/3.2/code/reason/snippet08.re b/src/content/3.2/code/reason/snippet08.re new file mode 100644 index 000000000..ec2bafac5 --- /dev/null +++ b/src/content/3.2/code/reason/snippet08.re @@ -0,0 +1,2 @@ +compose(fst, factorizer(p, q)) == p; +compose(snd, factorizer(p, q)) == q; diff --git a/src/content/3.2/code/reason/snippet09.re b/src/content/3.2/code/reason/snippet09.re new file mode 100644 index 000000000..f6b2b6a46 --- /dev/null +++ b/src/content/3.2/code/reason/snippet09.re @@ -0,0 +1 @@ +(int, bool) ~ (int, bool) diff --git a/src/content/3.3/code/reason/snippet01.re b/src/content/3.3/code/reason/snippet01.re new file mode 100644 index 000000000..778ed0946 --- /dev/null +++ b/src/content/3.3/code/reason/snippet01.re @@ -0,0 +1 @@ +type string = list(char); diff --git a/src/content/3.3/code/reason/snippet02.re b/src/content/3.3/code/reason/snippet02.re new file mode 100644 index 000000000..6f9f65cbc --- /dev/null +++ b/src/content/3.3/code/reason/snippet02.re @@ -0,0 +1,2 @@ +let to_nat: list(unit) => int = List.length; +let to_lst: int => list(unit) = n => List.init(n, ~f=_ => ()); diff --git a/src/content/3.4/code/reason/snippet01.re b/src/content/3.4/code/reason/snippet01.re new file mode 100644 index 000000000..d0d96e9ad --- /dev/null +++ b/src/content/3.4/code/reason/snippet01.re @@ -0,0 +1,11 @@ +/* Depends on OCaml library Core */ +module Vlen = (F: Functor with type t('a) = list('a)) => { + let summable: + module Base__.Container_intf.Summable with type t = float = + (module Float); + + let vlen = + Float.sqrt + <.> List.sum(summable, ~f=Fn.id) + <.> F.fmap(flip(Float.int_pow, 2)); +}; diff --git a/src/content/3.4/code/reason/snippet02.re b/src/content/3.4/code/reason/snippet02.re new file mode 100644 index 000000000..f50b8be20 --- /dev/null +++ b/src/content/3.4/code/reason/snippet02.re @@ -0,0 +1,6 @@ +module WriterInstance = (W: {type w;}) : + (Functor with type t('a) = writer(W.w, 'a)) => { + type t('a) = writer(W.w, 'a); + + let fmap = (f, Writer(a, w)) => Writer(f(a), w); +}; diff --git a/src/content/3.4/code/reason/snippet03.re b/src/content/3.4/code/reason/snippet03.re new file mode 100644 index 000000000..b174c88ad --- /dev/null +++ b/src/content/3.4/code/reason/snippet03.re @@ -0,0 +1 @@ +'a => writer('w, 'b) \ No newline at end of file diff --git a/src/content/3.4/code/reason/snippet04.re b/src/content/3.4/code/reason/snippet04.re new file mode 100644 index 000000000..605b088df --- /dev/null +++ b/src/content/3.4/code/reason/snippet04.re @@ -0,0 +1,6 @@ +module type Monad = { + type m('a); + + let (>=>): ('a => m('b), 'b => m('c), 'a) => m('c); + let return: 'a => m('a); +}; diff --git a/src/content/3.4/code/reason/snippet05.re b/src/content/3.4/code/reason/snippet05.re new file mode 100644 index 000000000..0136b07a3 --- /dev/null +++ b/src/content/3.4/code/reason/snippet05.re @@ -0,0 +1,12 @@ +module WriterMonad = (W: Monoid) : + (Monad with type m('a) = writer(W.a, 'a)) => { + type m('a) = writer(W.a, 'a); + + let (>=>) = (f, g, a) => { + let Writer(b, w) = f(a); + let Writer(c, w') = g(b); + Writer(c, W.mappend(w, w')); + }; + + let return = a => Writer(a, W.mempty); +}; diff --git a/src/content/3.4/code/reason/snippet06.re b/src/content/3.4/code/reason/snippet06.re new file mode 100644 index 000000000..71a6bc4cb --- /dev/null +++ b/src/content/3.4/code/reason/snippet06.re @@ -0,0 +1 @@ +let tell = w => Writer((), w); diff --git a/src/content/3.4/code/reason/snippet07.re b/src/content/3.4/code/reason/snippet07.re new file mode 100644 index 000000000..5bb7a7b76 --- /dev/null +++ b/src/content/3.4/code/reason/snippet07.re @@ -0,0 +1 @@ +let (>=>) = (f, g) => a => ... diff --git a/src/content/3.4/code/reason/snippet08.re b/src/content/3.4/code/reason/snippet08.re new file mode 100644 index 000000000..44d5b86ed --- /dev/null +++ b/src/content/3.4/code/reason/snippet08.re @@ -0,0 +1,4 @@ +let (>=>) = (f, g) => a => { + let mb = f(a); + ... +} \ No newline at end of file diff --git a/src/content/3.4/code/reason/snippet09.re b/src/content/3.4/code/reason/snippet09.re new file mode 100644 index 000000000..d7840ef6a --- /dev/null +++ b/src/content/3.4/code/reason/snippet09.re @@ -0,0 +1 @@ +let (>>=): (m('a), 'a => m('b)) => m('b); diff --git a/src/content/3.4/code/reason/snippet10.re b/src/content/3.4/code/reason/snippet10.re new file mode 100644 index 000000000..e8b020ec3 --- /dev/null +++ b/src/content/3.4/code/reason/snippet10.re @@ -0,0 +1,6 @@ +module type Monad_Bind = { + type m('a); + + let (>>=): (m('a), 'a => m('b)) => m('b); + let return: 'a => m('a); +}; diff --git a/src/content/3.4/code/reason/snippet11.re b/src/content/3.4/code/reason/snippet11.re new file mode 100644 index 000000000..a5c2eeaa4 --- /dev/null +++ b/src/content/3.4/code/reason/snippet11.re @@ -0,0 +1,6 @@ +module WriterMonadBind = (W: Monoid) => { + let (>>=) = (Writer(a, w), f) => { + let Writer(b, w') = f(a); + Writer(b, W.mappend(w, w')); + }; +}; diff --git a/src/content/3.4/code/reason/snippet12.re b/src/content/3.4/code/reason/snippet12.re new file mode 100644 index 000000000..acdd0fb64 --- /dev/null +++ b/src/content/3.4/code/reason/snippet12.re @@ -0,0 +1 @@ +let join: m(m('a)) => m('a) diff --git a/src/content/3.4/code/reason/snippet13.re b/src/content/3.4/code/reason/snippet13.re new file mode 100644 index 000000000..0f86c1e56 --- /dev/null +++ b/src/content/3.4/code/reason/snippet13.re @@ -0,0 +1,9 @@ +module BindUsingFunctionAndJoin = (F: Functor) => { + type m('a) = F.t('a); + + /** Make the type signature of join work + without providing an implementation **/ + external join: m(m('a)) => m('a) = "%identity"; + + let (>>=) = (ma, f) => join(F.fmap(f, ma)); +}; diff --git a/src/content/3.4/code/reason/snippet14.re b/src/content/3.4/code/reason/snippet14.re new file mode 100644 index 000000000..672acbe4b --- /dev/null +++ b/src/content/3.4/code/reason/snippet14.re @@ -0,0 +1,6 @@ +module type Monad_Join = (F: Functor) => { + type m('a) = F.t('a); + + let join: m(m('a)) => m('a); + let return: 'a => m('a); +}; diff --git a/src/content/3.4/code/reason/snippet15.re b/src/content/3.4/code/reason/snippet15.re new file mode 100644 index 000000000..616bce6cb --- /dev/null +++ b/src/content/3.4/code/reason/snippet15.re @@ -0,0 +1,3 @@ +module Fmap_Using_Monad = (M: Monad_Bind) => { + let fmap = (f, ma) => M.(>>=)(ma, a => M.return(f(a))); +}; diff --git a/src/content/3.4/code/reason/snippet16.re b/src/content/3.4/code/reason/snippet16.re new file mode 100644 index 000000000..1eb0bead5 --- /dev/null +++ b/src/content/3.4/code/reason/snippet16.re @@ -0,0 +1,3 @@ +module Writer_Join = (W: Monoid) => { + let join = (Writer(Writer(a, w'), w)) => Writer(a, W.mappend(w, w')); +}; diff --git a/src/content/3.4/code/reason/snippet17.re b/src/content/3.4/code/reason/snippet17.re new file mode 100644 index 000000000..d53576e30 --- /dev/null +++ b/src/content/3.4/code/reason/snippet17.re @@ -0,0 +1,7 @@ +/* Import Str module using this - #require "str" */ +let to_words = s => Writer(Str.split(Str.regexp("\b"), s), "to_words"); + +module Writer_Process = (W: Monad with type m('a) = + writer(string, 'a)) => { + let process = W.(up_case >=> to_words); +}; diff --git a/src/content/3.4/code/reason/snippet18.re b/src/content/3.4/code/reason/snippet18.re new file mode 100644 index 000000000..4c04e70db --- /dev/null +++ b/src/content/3.4/code/reason/snippet18.re @@ -0,0 +1,10 @@ +module Process_Do = (W: Monad_Bind with type m('a) = + writer(string, 'a)) => { + /* Needs Reason parser >= 3.6.0 */ + let (let*) = W.(>>=); + + let process = s => { + let* up_str = up_case(s); + to_words(up_str); + }; +}; diff --git a/src/content/3.4/code/reason/snippet19.re b/src/content/3.4/code/reason/snippet19.re new file mode 100644 index 000000000..d939ffef3 --- /dev/null +++ b/src/content/3.4/code/reason/snippet19.re @@ -0,0 +1 @@ +let up_case = s => Writer(String.uppercase(s), "up_case "); diff --git a/src/content/3.4/code/reason/snippet20.re b/src/content/3.4/code/reason/snippet20.re new file mode 100644 index 000000000..44c698d24 --- /dev/null +++ b/src/content/3.4/code/reason/snippet20.re @@ -0,0 +1,4 @@ +module Process_Bind_Without_Do = + (W: Monad_Bind with type m('a) = writer(string, 'a)) => { + let process = s => W.(up_case(s) >>= (up_str => to_words(up_str))); +}; diff --git a/src/content/3.4/code/reason/snippet21.re b/src/content/3.4/code/reason/snippet21.re new file mode 100644 index 000000000..8c0b0b71c --- /dev/null +++ b/src/content/3.4/code/reason/snippet21.re @@ -0,0 +1 @@ +up_str = up_case(s) \ No newline at end of file diff --git a/src/content/3.4/code/reason/snippet22.re b/src/content/3.4/code/reason/snippet22.re new file mode 100644 index 000000000..f3c87ae52 --- /dev/null +++ b/src/content/3.4/code/reason/snippet22.re @@ -0,0 +1,12 @@ +module Process_Tell = (W: Monad_Bind with type m('a) = + writer(string, 'a)) => { + /* Needs Reason parser >= 3.6.0 */ + let (let*) = W.(>>=); + let tell = w => Writer((), w); + + let process = s => { + let* up_str = up_case(s); + let* _ = tell("to_words "); + to_words(up_str); + }; +}; diff --git a/src/content/3.4/code/reason/snippet23.re b/src/content/3.4/code/reason/snippet23.re new file mode 100644 index 000000000..195a089ee --- /dev/null +++ b/src/content/3.4/code/reason/snippet23.re @@ -0,0 +1,10 @@ +module Process_Bind_Without_Do = + (W: Monad_Bind with type m('a) = writer(string, 'a)) => { + let tell = w => Writer((), w); + + let process = s => + W.( + up_case(s) + >>= (up_str => tell("to_words") >>= (_ => to_words(up_str))) + ); +}; diff --git a/src/content/3.4/code/reason/snippet24.re b/src/content/3.4/code/reason/snippet24.re new file mode 100644 index 000000000..7344bee7a --- /dev/null +++ b/src/content/3.4/code/reason/snippet24.re @@ -0,0 +1,3 @@ +module Monad_Ops = (M: Monad_Bind) => { + let (>>) = (m, k) => M.(m >>= (_ => k)); +}; diff --git a/src/content/3.4/code/reason/snippet25.re b/src/content/3.4/code/reason/snippet25.re new file mode 100644 index 000000000..e2b2e4e91 --- /dev/null +++ b/src/content/3.4/code/reason/snippet25.re @@ -0,0 +1,9 @@ +module Process_Bind_Without_Do = + (W: Monad_Bind with type m('a) = writer(string, 'a)) => { + open Monad_Ops(W); + + let tell = w => Writer((), w); + + let process = s => + W.(up_case(s) >>= (up_str => tell("to_words") >> to_words(up_str))); +}; diff --git a/src/content/3.5/code/reason/snippet01.re b/src/content/3.5/code/reason/snippet01.re new file mode 100644 index 000000000..deac5ae49 --- /dev/null +++ b/src/content/3.5/code/reason/snippet01.re @@ -0,0 +1,6 @@ +module List_Monad: Monad_Join = { + type m('a) = list('a); + + let join = List.concat; + let return = a => [a]; +}; diff --git a/src/content/3.5/code/reason/snippet02.re b/src/content/3.5/code/reason/snippet02.re new file mode 100644 index 000000000..b7b180e88 --- /dev/null +++ b/src/content/3.5/code/reason/snippet02.re @@ -0,0 +1 @@ +let (>>=) = (xs, k) => List.concat(List.map(k, xs)); diff --git a/src/content/3.5/code/reason/snippet03.re b/src/content/3.5/code/reason/snippet03.re new file mode 100644 index 000000000..4b004ba78 --- /dev/null +++ b/src/content/3.5/code/reason/snippet03.re @@ -0,0 +1,13 @@ +module Pythagorean = { + let (let*) = Fn.flip(Gen.flat_map); + let (let+) = (x, f) => Gen.map(f, x); + let guard = b => b ? Gen.return() ? Gen.empty; + + let triples = { + let* z = Gen.init(i => i + 1); + let* x = Gen.init(~limit=z, i => i + 1); + let* y = Gen.init(~limit=z, i => i + x); + let+ _ = guard(x * x + y * y == z * z); + Gen.return((x, y, z)); + }; +}; diff --git a/src/content/3.5/code/reason/snippet04.re b/src/content/3.5/code/reason/snippet04.re new file mode 100644 index 000000000..9c5ce0a56 --- /dev/null +++ b/src/content/3.5/code/reason/snippet04.re @@ -0,0 +1,4 @@ +let guard = + fun + | true => [()] + | false => []; diff --git a/src/content/3.5/code/reason/snippet05.re b/src/content/3.5/code/reason/snippet05.re new file mode 100644 index 000000000..e205004a5 --- /dev/null +++ b/src/content/3.5/code/reason/snippet05.re @@ -0,0 +1,16 @@ +module Pythagorean = { + let (let*) = Fn.flip(Gen.flat_map); + let (let+) = (x, f) => Gen.map(f, x); + let guard = b => b ? Gen.return() : Gen.empty; + + let triples = { + let* z = Gen.init(i => i + 1); + let* x = Gen.init(~limit=z, i => i + 1); + let* y = Gen.init(~limit=z, i => i + x); + if (x * x + y * y == z * z) { + Gen.return((x, y, z)); + } else { + Gen.empty; + }; + }; +}; diff --git a/src/content/3.5/code/reason/snippet06.re b/src/content/3.5/code/reason/snippet06.re new file mode 100644 index 000000000..14db1f232 --- /dev/null +++ b/src/content/3.5/code/reason/snippet06.re @@ -0,0 +1,2 @@ +type reader('e, 'a) = + | Reader('e => 'a); diff --git a/src/content/3.5/code/reason/snippet07.re b/src/content/3.5/code/reason/snippet07.re new file mode 100644 index 000000000..02fe5477b --- /dev/null +++ b/src/content/3.5/code/reason/snippet07.re @@ -0,0 +1 @@ +let run_reader = (Reader(f), e) => f(e); diff --git a/src/content/3.5/code/reason/snippet08.re b/src/content/3.5/code/reason/snippet08.re new file mode 100644 index 000000000..0d4701bff --- /dev/null +++ b/src/content/3.5/code/reason/snippet08.re @@ -0,0 +1 @@ +let (>>=) = (ra, k) => Reader(e => ...); diff --git a/src/content/3.5/code/reason/snippet09.re b/src/content/3.5/code/reason/snippet09.re new file mode 100644 index 000000000..25dda0f1d --- /dev/null +++ b/src/content/3.5/code/reason/snippet09.re @@ -0,0 +1,4 @@ +let (>>=) = (ra, k) => Reader(e => { + let a = run_reader(ra, e); + ... +}); \ No newline at end of file diff --git a/src/content/3.5/code/reason/snippet10.re b/src/content/3.5/code/reason/snippet10.re new file mode 100644 index 000000000..13cd7759a --- /dev/null +++ b/src/content/3.5/code/reason/snippet10.re @@ -0,0 +1,5 @@ +let (>>=) = (ra, k) => Reader(e => { + let a = run_reader(ra, e); + let rb = k(a); + ... +}); \ No newline at end of file diff --git a/src/content/3.5/code/reason/snippet11.re b/src/content/3.5/code/reason/snippet11.re new file mode 100644 index 000000000..0ddaafed9 --- /dev/null +++ b/src/content/3.5/code/reason/snippet11.re @@ -0,0 +1,5 @@ +let (>>=) = (ra, k) => Reader(e => { + let a = run_reader(ra, e); + let rb = k(a); + run_reader(rb, e); +}); diff --git a/src/content/3.5/code/reason/snippet12.re b/src/content/3.5/code/reason/snippet12.re new file mode 100644 index 000000000..eb877302f --- /dev/null +++ b/src/content/3.5/code/reason/snippet12.re @@ -0,0 +1,8 @@ +module ReaderMonad = (T: {type t;}) : Monad_Bind => { + type m('a) = reader(T.t, 'a); + + let return = a => Reader(e => a); + + let (>>=) = (ra, k) => + Reader(e => run_reader(k(run_reader(ra, e)), e)); +}; diff --git a/src/content/3.5/code/reason/snippet13.re b/src/content/3.5/code/reason/snippet13.re new file mode 100644 index 000000000..22cdf1f14 --- /dev/null +++ b/src/content/3.5/code/reason/snippet13.re @@ -0,0 +1,2 @@ +type writer('w, 'a) = + | Writer(('a, 'w)); diff --git a/src/content/3.5/code/reason/snippet14.re b/src/content/3.5/code/reason/snippet14.re new file mode 100644 index 000000000..aa1eabdbb --- /dev/null +++ b/src/content/3.5/code/reason/snippet14.re @@ -0,0 +1 @@ +let run_writer = (Writer(a, w)) => (a, w); diff --git a/src/content/3.5/code/reason/snippet15.re b/src/content/3.5/code/reason/snippet15.re new file mode 100644 index 000000000..995b57950 --- /dev/null +++ b/src/content/3.5/code/reason/snippet15.re @@ -0,0 +1,10 @@ +module WriterMonad = (W: Monoid) : Monad_Bind => { + type m('a) = writer(W.t, 'a); + + let return = a => Writer(a, W.mempty); + + let (>>=) = (Writer(a, w), k) => { + let (a', w') = run_writer(k(a)); + Writer(a', W.mappend(w, w')); + }; +}; diff --git a/src/content/3.5/code/reason/snippet16.re b/src/content/3.5/code/reason/snippet16.re new file mode 100644 index 000000000..b9f53801e --- /dev/null +++ b/src/content/3.5/code/reason/snippet16.re @@ -0,0 +1,2 @@ +type state('s, 'a) = + | State('s => ('a, 's)); diff --git a/src/content/3.5/code/reason/snippet17.re b/src/content/3.5/code/reason/snippet17.re new file mode 100644 index 000000000..ad999c1b8 --- /dev/null +++ b/src/content/3.5/code/reason/snippet17.re @@ -0,0 +1 @@ +let run_state = (State(f), s) => f(s); diff --git a/src/content/3.5/code/reason/snippet18.re b/src/content/3.5/code/reason/snippet18.re new file mode 100644 index 000000000..4f83a5e73 --- /dev/null +++ b/src/content/3.5/code/reason/snippet18.re @@ -0,0 +1,5 @@ +let (>>=) = (sa, k) => State(s => { + let (a, s') = run_state(sa, s); + let sb = k(a); + run_state(sb, s'); +}); diff --git a/src/content/3.5/code/reason/snippet19.re b/src/content/3.5/code/reason/snippet19.re new file mode 100644 index 000000000..5996d64b6 --- /dev/null +++ b/src/content/3.5/code/reason/snippet19.re @@ -0,0 +1,11 @@ +module State_Monad = (S: {type t;}) : Monad_Bind => { + type m('a) = state(S.t, 'a); + + let (>>=) = (sa, k) => State(s => { + let (a, s') = run_state(sa, s); + let sb = k(a); + run_state(sb, s'); + }); + + let return = a => State(s => (a, s)); +}; diff --git a/src/content/3.5/code/reason/snippet20.re b/src/content/3.5/code/reason/snippet20.re new file mode 100644 index 000000000..391070cd6 --- /dev/null +++ b/src/content/3.5/code/reason/snippet20.re @@ -0,0 +1 @@ +let get = State(s => (s, s)); diff --git a/src/content/3.5/code/reason/snippet21.re b/src/content/3.5/code/reason/snippet21.re new file mode 100644 index 000000000..9db3626f4 --- /dev/null +++ b/src/content/3.5/code/reason/snippet21.re @@ -0,0 +1 @@ +let put = s' => State(s => ((), s')); diff --git a/src/content/3.5/code/reason/snippet22.re b/src/content/3.5/code/reason/snippet22.re new file mode 100644 index 000000000..2ca28d1af --- /dev/null +++ b/src/content/3.5/code/reason/snippet22.re @@ -0,0 +1,10 @@ +module OptionMonad: Monad_Bind = { + type m('a) = option('a); + + let (>>=) = + fun + | Some(a) => (k => k(a)) + | None => (_ => None); + + let return = a => Some(a); +}; diff --git a/src/content/3.5/code/reason/snippet23.re b/src/content/3.5/code/reason/snippet23.re new file mode 100644 index 000000000..2fc9e36c3 --- /dev/null +++ b/src/content/3.5/code/reason/snippet23.re @@ -0,0 +1,2 @@ +type cont('r, 'a) = + | Cont(('a => 'r) => 'r); diff --git a/src/content/3.5/code/reason/snippet24.re b/src/content/3.5/code/reason/snippet24.re new file mode 100644 index 000000000..38ab609f3 --- /dev/null +++ b/src/content/3.5/code/reason/snippet24.re @@ -0,0 +1 @@ +let run_cont = (Cont(k), h) => k(h); diff --git a/src/content/3.5/code/reason/snippet25.re b/src/content/3.5/code/reason/snippet25.re new file mode 100644 index 000000000..58dfa0a36 --- /dev/null +++ b/src/content/3.5/code/reason/snippet25.re @@ -0,0 +1,3 @@ +let (>>=): (('a => 'r) => 'r, + ('a, 'b => 'r) => 'r, + 'b => 'r) => 'r; diff --git a/src/content/3.5/code/reason/snippet26.re b/src/content/3.5/code/reason/snippet26.re new file mode 100644 index 000000000..970c366d1 --- /dev/null +++ b/src/content/3.5/code/reason/snippet26.re @@ -0,0 +1 @@ +let (>>=) = (ka, kab) => Cont(hb => ...); diff --git a/src/content/3.5/code/reason/snippet27.re b/src/content/3.5/code/reason/snippet27.re new file mode 100644 index 000000000..03f4d412d --- /dev/null +++ b/src/content/3.5/code/reason/snippet27.re @@ -0,0 +1 @@ +run_cont(ka, a => ...); diff --git a/src/content/3.5/code/reason/snippet28.re b/src/content/3.5/code/reason/snippet28.re new file mode 100644 index 000000000..41ccfee0e --- /dev/null +++ b/src/content/3.5/code/reason/snippet28.re @@ -0,0 +1,4 @@ +run_cont(ka,a => { + let kb = kab(a); + run_cont(kb, hb); +}); diff --git a/src/content/3.5/code/reason/snippet29.re b/src/content/3.5/code/reason/snippet29.re new file mode 100644 index 000000000..643128e61 --- /dev/null +++ b/src/content/3.5/code/reason/snippet29.re @@ -0,0 +1,8 @@ +module Cont_Monad = (R: {type t;}) : Monad_Bind => { + type m('a) = cont(R.t, 'a); + + let return = a => Cont(ha => ha(a)); + + let (>>=) = (ka, kab) => + Cont(hb => run_cont(ka, a => run_cont(kab(a), hb))); +}; diff --git a/src/content/3.5/code/reason/snippet30.re b/src/content/3.5/code/reason/snippet30.re new file mode 100644 index 000000000..df5b8661a --- /dev/null +++ b/src/content/3.5/code/reason/snippet30.re @@ -0,0 +1,7 @@ +module type Terminal_IO = { + /* ReasonML doesn't have a built-in IO type*/ + type io('a) = + | IO(unit => 'a); + + let get_char: unit => io(char); +}; diff --git a/src/content/3.5/code/reason/snippet31.re b/src/content/3.5/code/reason/snippet31.re new file mode 100644 index 000000000..9e0e8f8ce --- /dev/null +++ b/src/content/3.5/code/reason/snippet31.re @@ -0,0 +1 @@ +let main: io(unit); diff --git a/src/content/3.5/code/reason/snippet32.re b/src/content/3.5/code/reason/snippet32.re new file mode 100644 index 000000000..ae7826b47 --- /dev/null +++ b/src/content/3.5/code/reason/snippet32.re @@ -0,0 +1 @@ +let main: unit => io(unit); diff --git a/src/content/3.5/code/reason/snippet33.re b/src/content/3.5/code/reason/snippet33.re new file mode 100644 index 000000000..505723240 --- /dev/null +++ b/src/content/3.5/code/reason/snippet33.re @@ -0,0 +1 @@ +type io('a) = realworld => ('a, realworld); diff --git a/src/content/3.5/code/reason/snippet34.re b/src/content/3.5/code/reason/snippet34.re new file mode 100644 index 000000000..77f7a6c13 --- /dev/null +++ b/src/content/3.5/code/reason/snippet34.re @@ -0,0 +1 @@ +type io('a) = state(realworld); diff --git a/src/content/3.5/code/reason/snippet35.re b/src/content/3.5/code/reason/snippet35.re new file mode 100644 index 000000000..16e57d8e2 --- /dev/null +++ b/src/content/3.5/code/reason/snippet35.re @@ -0,0 +1 @@ +let put_str: string => io(unit); diff --git a/src/content/3.5/code/reason/snippet36.re b/src/content/3.5/code/reason/snippet36.re new file mode 100644 index 000000000..9d0fd7cab --- /dev/null +++ b/src/content/3.5/code/reason/snippet36.re @@ -0,0 +1 @@ +let put_str: string => unit; diff --git a/src/content/3.5/code/reason/snippet37.re b/src/content/3.5/code/reason/snippet37.re new file mode 100644 index 000000000..c7fa04013 --- /dev/null +++ b/src/content/3.5/code/reason/snippet37.re @@ -0,0 +1,22 @@ +/* Monad implementation for type io */ +module IOMonad: Monad_Bind with type m('a) = io('a) = { + type m('a) = io('a); + + let return = x => IO(() => x); + + let (>>=) = (m, f) => IO(() => { + let IO(m') = m; + let IO(m'') = f(m'()); + m''(); + }); +}; + +/* main */ +module IO_Main = { + let (let*) = IOMonad.(>>=); + + let main = { + let* _ = put_str("Hello"); + put_str("world!"); + }; +}; diff --git a/src/content/3.6/code/reason/snippet01.re b/src/content/3.6/code/reason/snippet01.re new file mode 100644 index 000000000..90cdbbb59 --- /dev/null +++ b/src/content/3.6/code/reason/snippet01.re @@ -0,0 +1,5 @@ +module Kleisli = (M: MonadJoin) => { + /* compose */ + let (<.>) = (f, g, x) => f(g(x)); + let (>=>) = (f, g) => M.join <.> M.fmap(g) <.> f; +}; diff --git a/src/content/3.6/code/reason/snippet02.re b/src/content/3.6/code/reason/snippet02.re new file mode 100644 index 000000000..38fec1103 --- /dev/null +++ b/src/content/3.6/code/reason/snippet02.re @@ -0,0 +1,3 @@ +module Kleisli = (M: MonadJoin) => { + let (>=>) = (f, g, a) => M.join(M.fmap(g, f(a))); +}; diff --git a/src/content/3.6/code/reason/snippet03.re b/src/content/3.6/code/reason/snippet03.re new file mode 100644 index 000000000..36c017e22 --- /dev/null +++ b/src/content/3.6/code/reason/snippet03.re @@ -0,0 +1,6 @@ +module type Monoid = { + type m; + + let mappend: (m, m) => m; + let mempty: m; +}; diff --git a/src/content/3.6/code/reason/snippet04.re b/src/content/3.6/code/reason/snippet04.re new file mode 100644 index 000000000..eb4ce6f09 --- /dev/null +++ b/src/content/3.6/code/reason/snippet04.re @@ -0,0 +1 @@ +let mappend: (m, m) => m; diff --git a/src/content/3.6/code/reason/snippet05.re b/src/content/3.6/code/reason/snippet05.re new file mode 100644 index 000000000..107537b6e --- /dev/null +++ b/src/content/3.6/code/reason/snippet05.re @@ -0,0 +1 @@ +let mu: (m, m) => m; diff --git a/src/content/3.6/code/reason/snippet06.re b/src/content/3.6/code/reason/snippet06.re new file mode 100644 index 000000000..ed94be075 --- /dev/null +++ b/src/content/3.6/code/reason/snippet06.re @@ -0,0 +1 @@ +let eta: unit => m = ; diff --git a/src/content/3.6/code/reason/snippet07.re b/src/content/3.6/code/reason/snippet07.re new file mode 100644 index 000000000..b0ad64750 --- /dev/null +++ b/src/content/3.6/code/reason/snippet07.re @@ -0,0 +1,2 @@ + +mu((x, mu((y, z)))) == mu((mu((x, y)), z)); diff --git a/src/content/3.6/code/reason/snippet08.re b/src/content/3.6/code/reason/snippet08.re new file mode 100644 index 000000000..33015a9d5 --- /dev/null +++ b/src/content/3.6/code/reason/snippet08.re @@ -0,0 +1,2 @@ + +(compose(mu, bimap(id, mu)))((x, (y, z))); diff --git a/src/content/3.6/code/reason/snippet09.re b/src/content/3.6/code/reason/snippet09.re new file mode 100644 index 000000000..996732b6b --- /dev/null +++ b/src/content/3.6/code/reason/snippet09.re @@ -0,0 +1,2 @@ + +(compose(mu, bimap(mu, id)))(((x, y), z)); diff --git a/src/content/3.6/code/reason/snippet10.re b/src/content/3.6/code/reason/snippet10.re new file mode 100644 index 000000000..77a8a751d --- /dev/null +++ b/src/content/3.6/code/reason/snippet10.re @@ -0,0 +1,2 @@ + +compose(mu, bimap(id, mu)) == compose(mu, bimap(mu, id)); diff --git a/src/content/3.6/code/reason/snippet11.re b/src/content/3.6/code/reason/snippet11.re new file mode 100644 index 000000000..2e1695476 --- /dev/null +++ b/src/content/3.6/code/reason/snippet11.re @@ -0,0 +1 @@ +let alpha = (((x, y), z)) => (x, (y, z)); diff --git a/src/content/3.6/code/reason/snippet12.re b/src/content/3.6/code/reason/snippet12.re new file mode 100644 index 000000000..7afbe929b --- /dev/null +++ b/src/content/3.6/code/reason/snippet12.re @@ -0,0 +1,2 @@ + +compose(mu, compose(bimap(id, mu), alpha)) == compose(mu, bimap(mu, id)); diff --git a/src/content/3.6/code/reason/snippet13.re b/src/content/3.6/code/reason/snippet13.re new file mode 100644 index 000000000..dc5a6c6af --- /dev/null +++ b/src/content/3.6/code/reason/snippet13.re @@ -0,0 +1,2 @@ + +mu((eta(), x)) == x(mu, (x, eta())) == x; diff --git a/src/content/3.6/code/reason/snippet14.re b/src/content/3.6/code/reason/snippet14.re new file mode 100644 index 000000000..a69bef038 --- /dev/null +++ b/src/content/3.6/code/reason/snippet14.re @@ -0,0 +1,4 @@ + +(compose(mu, bimap(eta, id)))(((), x)) +== lambda(((), x), compose(mu, bimap(id, eta)), (x, ())) +== rho((x, ())); diff --git a/src/content/3.6/code/reason/snippet15.re b/src/content/3.6/code/reason/snippet15.re new file mode 100644 index 000000000..99ccb8936 --- /dev/null +++ b/src/content/3.6/code/reason/snippet15.re @@ -0,0 +1 @@ +let lambda = (((), x)) => x; diff --git a/src/content/3.6/code/reason/snippet16.re b/src/content/3.6/code/reason/snippet16.re new file mode 100644 index 000000000..9ad02fa2c --- /dev/null +++ b/src/content/3.6/code/reason/snippet16.re @@ -0,0 +1 @@ +let rho = ((x, ())) => x; diff --git a/src/content/3.6/code/reason/snippet17.re b/src/content/3.6/code/reason/snippet17.re new file mode 100644 index 000000000..e973db06d --- /dev/null +++ b/src/content/3.6/code/reason/snippet17.re @@ -0,0 +1 @@ +mu.bimap(id, eta) == rho(mu.bimap, eta, id) == lambda; diff --git a/src/content/3.6/code/reason/snippet18.re b/src/content/3.6/code/reason/snippet18.re new file mode 100644 index 000000000..b9f53801e --- /dev/null +++ b/src/content/3.6/code/reason/snippet18.re @@ -0,0 +1,2 @@ +type state('s, 'a) = + | State('s => ('a, 's)); diff --git a/src/content/3.6/code/reason/snippet19.re b/src/content/3.6/code/reason/snippet19.re new file mode 100644 index 000000000..e90a09d72 --- /dev/null +++ b/src/content/3.6/code/reason/snippet19.re @@ -0,0 +1,2 @@ +type prod('s, 'a) = + | Prod('a, 's); diff --git a/src/content/3.6/code/reason/snippet20.re b/src/content/3.6/code/reason/snippet20.re new file mode 100644 index 000000000..c170520c6 --- /dev/null +++ b/src/content/3.6/code/reason/snippet20.re @@ -0,0 +1,2 @@ +type reader('s, 'a) = + | Reader('s => 'a); diff --git a/src/content/3.6/code/reason/snippet21.re b/src/content/3.6/code/reason/snippet21.re new file mode 100644 index 000000000..7a8f17c5e --- /dev/null +++ b/src/content/3.6/code/reason/snippet21.re @@ -0,0 +1,14 @@ +module AdjunctionState = ( + S: {type s;}, + F: Functor with type t('a) = prod(S.s, 'a), + R: Representable with type t('a) = reader(S.s, 'a), + ): Adjunction => { + type f('a) = prod(S.s, 'a); + type r('a) = reader(S.s, 'a); + + include F; + include R; + + let unit = a => Reader(s => Prod(a, s)); + let counit = (Prod(Reader(f), s)) => f(s); +}; diff --git a/src/content/3.6/code/reason/snippet22.re b/src/content/3.6/code/reason/snippet22.re new file mode 100644 index 000000000..b9f53801e --- /dev/null +++ b/src/content/3.6/code/reason/snippet22.re @@ -0,0 +1,2 @@ +type state('s, 'a) = + | State('s => ('a, 's)); diff --git a/src/content/3.6/code/reason/snippet23.re b/src/content/3.6/code/reason/snippet23.re new file mode 100644 index 000000000..ad999c1b8 --- /dev/null +++ b/src/content/3.6/code/reason/snippet23.re @@ -0,0 +1 @@ +let run_state = (State(f), s) => f(s); diff --git a/src/content/3.6/code/reason/snippet24.re b/src/content/3.6/code/reason/snippet24.re new file mode 100644 index 000000000..1c8ac5488 --- /dev/null +++ b/src/content/3.6/code/reason/snippet24.re @@ -0,0 +1,2 @@ +let ssa: state('s, state('s, 'a)); +let run_state ssa: 's => (state('s, 'a), 's); \ No newline at end of file diff --git a/src/content/3.6/code/reason/snippet25.re b/src/content/3.6/code/reason/snippet25.re new file mode 100644 index 000000000..1e228736e --- /dev/null +++ b/src/content/3.6/code/reason/snippet25.re @@ -0,0 +1,4 @@ +let join: state('s, state('s, 'a)) => state('s, 'a) = ( + ssa => State(uncurry(run_state) <.> run_state(ssa)): + state('s, state('s, 'a)) => state('s, 'a) +); diff --git a/src/content/3.7/code/reason/snippet01.re b/src/content/3.7/code/reason/snippet01.re new file mode 100644 index 000000000..819bac6c8 --- /dev/null +++ b/src/content/3.7/code/reason/snippet01.re @@ -0,0 +1 @@ +'a => m('b); \ No newline at end of file diff --git a/src/content/3.7/code/reason/snippet02.re b/src/content/3.7/code/reason/snippet02.re new file mode 100644 index 000000000..7c783dc14 --- /dev/null +++ b/src/content/3.7/code/reason/snippet02.re @@ -0,0 +1 @@ +w('a) => 'b; \ No newline at end of file diff --git a/src/content/3.7/code/reason/snippet03.re b/src/content/3.7/code/reason/snippet03.re new file mode 100644 index 000000000..ba5cb1cdb --- /dev/null +++ b/src/content/3.7/code/reason/snippet03.re @@ -0,0 +1,5 @@ +module type CoKleisli = { + type w('a); + + let (=>=): (w('a) => 'b, w('b) => 'c, w('a)) => 'c; +}; diff --git a/src/content/3.7/code/reason/snippet04.re b/src/content/3.7/code/reason/snippet04.re new file mode 100644 index 000000000..e8eb1f3b4 --- /dev/null +++ b/src/content/3.7/code/reason/snippet04.re @@ -0,0 +1 @@ +let extract: w('a) => 'a; diff --git a/src/content/3.7/code/reason/snippet05.re b/src/content/3.7/code/reason/snippet05.re new file mode 100644 index 000000000..a94143f65 --- /dev/null +++ b/src/content/3.7/code/reason/snippet05.re @@ -0,0 +1,8 @@ +module type Comonad = { + type w('a); + + include Functor with type t('a) := w('a); + + let extract: w('a) => 'a; + let (=>=): (w('a) => 'b, w('b) => 'c, w('a)) => 'c; +}; diff --git a/src/content/3.7/code/reason/snippet06.re b/src/content/3.7/code/reason/snippet06.re new file mode 100644 index 000000000..a4774716a --- /dev/null +++ b/src/content/3.7/code/reason/snippet06.re @@ -0,0 +1 @@ +(('a, 'e)) => 'b; \ No newline at end of file diff --git a/src/content/3.7/code/reason/snippet07.re b/src/content/3.7/code/reason/snippet07.re new file mode 100644 index 000000000..107a9362b --- /dev/null +++ b/src/content/3.7/code/reason/snippet07.re @@ -0,0 +1 @@ +('a, 'e) => 'b; \ No newline at end of file diff --git a/src/content/3.7/code/reason/snippet08.re b/src/content/3.7/code/reason/snippet08.re new file mode 100644 index 000000000..310ec32d6 --- /dev/null +++ b/src/content/3.7/code/reason/snippet08.re @@ -0,0 +1,2 @@ +type product('e, 'a) = + | P('e, 'a); diff --git a/src/content/3.7/code/reason/snippet09.re b/src/content/3.7/code/reason/snippet09.re new file mode 100644 index 000000000..e27bfed80 --- /dev/null +++ b/src/content/3.7/code/reason/snippet09.re @@ -0,0 +1,5 @@ +let (=>=) = (f, g, P(e, a)) => { + let b = f(P(e, a)); + let c = g(P(e, b)); + c; +}; diff --git a/src/content/3.7/code/reason/snippet10.re b/src/content/3.7/code/reason/snippet10.re new file mode 100644 index 000000000..52df26340 --- /dev/null +++ b/src/content/3.7/code/reason/snippet10.re @@ -0,0 +1 @@ +let extract = (P(e, a)) => a; diff --git a/src/content/3.7/code/reason/snippet11.re b/src/content/3.7/code/reason/snippet11.re new file mode 100644 index 000000000..7af45b2e3 --- /dev/null +++ b/src/content/3.7/code/reason/snippet11.re @@ -0,0 +1,5 @@ +module CoKleisliImpl = { + type w('a); + let (=>=): (w('a) => 'b, w('b) => 'c, w('a)) => 'c = (f, g) => + g ... +}; diff --git a/src/content/3.7/code/reason/snippet12.re b/src/content/3.7/code/reason/snippet12.re new file mode 100644 index 000000000..e3a17cd35 --- /dev/null +++ b/src/content/3.7/code/reason/snippet12.re @@ -0,0 +1 @@ +let extend: (w('a) => 'b, w('a)) => w('b); diff --git a/src/content/3.7/code/reason/snippet13.re b/src/content/3.7/code/reason/snippet13.re new file mode 100644 index 000000000..e3e7a7fcc --- /dev/null +++ b/src/content/3.7/code/reason/snippet13.re @@ -0,0 +1,14 @@ +module type CoKleisliExtend = { + type w('a); + + let extend: (w('a) => 'b, w('a)) => w('b); +}; + +module CoKleisliImpl = (C: CoKleisliExtend) => { + type w('a) = C.w('a); + + let (=>=): (w('a) => 'b, w('b) => 'c, w('a)) => 'c = ( + (f, g) => compose(g, C.extend(f)): + (w('a) => 'b, w('b) => 'c, w('a)) => 'c + ); +}; diff --git a/src/content/3.7/code/reason/snippet14.re b/src/content/3.7/code/reason/snippet14.re new file mode 100644 index 000000000..af7afaf4a --- /dev/null +++ b/src/content/3.7/code/reason/snippet14.re @@ -0,0 +1 @@ +let duplicate: w('a) => w(w('a)); diff --git a/src/content/3.7/code/reason/snippet15.re b/src/content/3.7/code/reason/snippet15.re new file mode 100644 index 000000000..88863e175 --- /dev/null +++ b/src/content/3.7/code/reason/snippet15.re @@ -0,0 +1,49 @@ +module type ComonadBase = { + type w('a); + + include Functor with type t('a) = w('a); + + let extract: w('a) => 'a; +}; + +module type ComonadDuplicate = { + type w('a); + + let duplicate: w('a) => w(w('a)); +}; + +module type ComonadExtend = { + type w('a); + + let extend: (w('a) => 'b, w('a)) => w('b); +}; + +module type Comonad = { + type w('a); + + include ComonadBase with type w('a) := w('a); + include ComonadExtend with type w('a) := w('a); + include ComonadDuplicate with type w('a) := w('a); +}; + +/* Construct a full comonad instance using one of the +* following modules */ +module ComonadImplViaExtend: + (C: ComonadBase, D: ComonadDuplicate with type w('a) = C.w('a)) => + Comonad with type w('a) = C.w('a) = + (C: ComonadBase, D: ComonadDuplicate with type w('a) = C.w('a)) => { + include C; + include D; + + let extend = (f, wa) => (C.fmap(f))(D.duplicate(wa)); + }; + +module ComonadImplViaDuplicate: + (C: ComonadBase, E: ComonadExtend with type w('a) = C.w('a)) => + Comonad with type w('a) = C.w('a) = + (C: ComonadBase, E: ComonadExtend with type w('a) = C.w('a)) => { + include C; + include E; + + let duplicate = (wa: w('a)): w(w('a)) => E.extend(id, wa); + }; diff --git a/src/content/3.7/code/reason/snippet16.re b/src/content/3.7/code/reason/snippet16.re new file mode 100644 index 000000000..aec142ec7 --- /dev/null +++ b/src/content/3.7/code/reason/snippet16.re @@ -0,0 +1,2 @@ +type stream('a) = + | Cons('a, Lazy.t(stream('a))); diff --git a/src/content/3.7/code/reason/snippet17.re b/src/content/3.7/code/reason/snippet17.re new file mode 100644 index 000000000..ea6893891 --- /dev/null +++ b/src/content/3.7/code/reason/snippet17.re @@ -0,0 +1,7 @@ +module StreamFunctor: Functor with type t('a) = stream('a) = { + type t('a) = stream('a); + + let rec fmap = f => + fun + | Cons(x, xs) => Cons(f(x), Lazy.from_val(fmap(f, Lazy.force(xs)))); +}; diff --git a/src/content/3.7/code/reason/snippet18.re b/src/content/3.7/code/reason/snippet18.re new file mode 100644 index 000000000..25d97c458 --- /dev/null +++ b/src/content/3.7/code/reason/snippet18.re @@ -0,0 +1 @@ +let extract = (Cons(x, _)) => x; diff --git a/src/content/3.7/code/reason/snippet19.re b/src/content/3.7/code/reason/snippet19.re new file mode 100644 index 000000000..be97e7e05 --- /dev/null +++ b/src/content/3.7/code/reason/snippet19.re @@ -0,0 +1,2 @@ +let rec duplicate = (Cons(x, xs)) => + Cons(Cons(x, xs), Lazy.from_val(duplicate(Lazy.force(xs)))); diff --git a/src/content/3.7/code/reason/snippet20.re b/src/content/3.7/code/reason/snippet20.re new file mode 100644 index 000000000..41347b865 --- /dev/null +++ b/src/content/3.7/code/reason/snippet20.re @@ -0,0 +1,26 @@ +/* Implement Extract */ +module StreamComonadBase = + (F: Functor with type t('a) = stream('a)) + : (ComonadBase with type w('a) = stream('a)) => { + type w('a) = stream('a); + + include F; + + let extract = (Cons(x, _)) => x; +}; + +/* Implement duplicate */ +module StreamComonadDuplicate: ComonadDuplicate with type w('a) = + stream('a) = { + type w('a) = stream('a); + + let rec duplicate = (Cons(x, xs)) => + Cons(Cons(x, xs), Lazy.from_val(duplicate(Lazy.force(xs)))); +}; + +/* Generate full Comonad Instance */ +module StreamComonad: Comonad with type w('a) = stream('a) = + ComonadImplViaExtend( + (StreamComonadBase(StreamFunctor)), + StreamComonadDuplicate, + ); diff --git a/src/content/3.7/code/reason/snippet21.re b/src/content/3.7/code/reason/snippet21.re new file mode 100644 index 000000000..38d254260 --- /dev/null +++ b/src/content/3.7/code/reason/snippet21.re @@ -0,0 +1 @@ +let tail = (Cons(_, xs)) => Lazy.force(xs); diff --git a/src/content/3.7/code/reason/snippet22.re b/src/content/3.7/code/reason/snippet22.re new file mode 100644 index 000000000..e40463228 --- /dev/null +++ b/src/content/3.7/code/reason/snippet22.re @@ -0,0 +1,2 @@ +let rec sum_s = (n, Cons(x, xs)) => + n <= 0 ? 0 : x + sum_s(n - 1, Lazy.force(xs)) diff --git a/src/content/3.7/code/reason/snippet23.re b/src/content/3.7/code/reason/snippet23.re new file mode 100644 index 000000000..590c07c69 --- /dev/null +++ b/src/content/3.7/code/reason/snippet23.re @@ -0,0 +1 @@ +let average = (n, stm) => Float.(of_int(sum_s(n, stm)) /. of_int(n)); diff --git a/src/content/3.7/code/reason/snippet24.re b/src/content/3.7/code/reason/snippet24.re new file mode 100644 index 000000000..28a923cf1 --- /dev/null +++ b/src/content/3.7/code/reason/snippet24.re @@ -0,0 +1 @@ +let moving_average = n => StreamComonad.extend(average(n)); diff --git a/src/content/3.7/code/reason/snippet25.re b/src/content/3.7/code/reason/snippet25.re new file mode 100644 index 000000000..e683ec8a2 --- /dev/null +++ b/src/content/3.7/code/reason/snippet25.re @@ -0,0 +1,6 @@ +module type Comonoid = { + type m; + + let split: m => (m, m); + let destroy: m => unit; +}; diff --git a/src/content/3.7/code/reason/snippet26.re b/src/content/3.7/code/reason/snippet26.re new file mode 100644 index 000000000..1ef26376e --- /dev/null +++ b/src/content/3.7/code/reason/snippet26.re @@ -0,0 +1 @@ +let destroy = _ => (); diff --git a/src/content/3.7/code/reason/snippet27.re b/src/content/3.7/code/reason/snippet27.re new file mode 100644 index 000000000..328dd475d --- /dev/null +++ b/src/content/3.7/code/reason/snippet27.re @@ -0,0 +1 @@ +let split = x => (f(x), g(x)); diff --git a/src/content/3.7/code/reason/snippet28.re b/src/content/3.7/code/reason/snippet28.re new file mode 100644 index 000000000..cc2f797c4 --- /dev/null +++ b/src/content/3.7/code/reason/snippet28.re @@ -0,0 +1,8 @@ +/* lambda is the left unitor and rho is the right unitor */ +/* <.> is used as compose below */ + +lambda +<.> bimap(destroy, id) +<.> split == id(rho) +<.> bimap(id, destroy) +<.> split == id; diff --git a/src/content/3.7/code/reason/snippet29.re b/src/content/3.7/code/reason/snippet29.re new file mode 100644 index 000000000..9322244a1 --- /dev/null +++ b/src/content/3.7/code/reason/snippet29.re @@ -0,0 +1,4 @@ +lambda(bimap(destroy, id, split(x))) +== lambda(bimap(destroy, id, (f(x), g(x)))) +== lambda(((), g(x))) +== g(x); diff --git a/src/content/3.7/code/reason/snippet30.re b/src/content/3.7/code/reason/snippet30.re new file mode 100644 index 000000000..ba5144a3d --- /dev/null +++ b/src/content/3.7/code/reason/snippet30.re @@ -0,0 +1 @@ +let split = x => (x, x); diff --git a/src/content/3.7/code/reason/snippet31.re b/src/content/3.7/code/reason/snippet31.re new file mode 100644 index 000000000..cd90f6f4e --- /dev/null +++ b/src/content/3.7/code/reason/snippet31.re @@ -0,0 +1,2 @@ +type store('s, 'a) = + | Store(('s => 'a, 's)); diff --git a/src/content/3.7/code/reason/snippet32.re b/src/content/3.7/code/reason/snippet32.re new file mode 100644 index 000000000..58cfa984b --- /dev/null +++ b/src/content/3.7/code/reason/snippet32.re @@ -0,0 +1 @@ +let counit = (Prod(Reader(f), s)) => f(s); diff --git a/src/content/3.7/code/reason/snippet33.re b/src/content/3.7/code/reason/snippet33.re new file mode 100644 index 000000000..6d910eaea --- /dev/null +++ b/src/content/3.7/code/reason/snippet33.re @@ -0,0 +1 @@ +let extract = (Store(f, s)) => f(s); diff --git a/src/content/3.7/code/reason/snippet34.re b/src/content/3.7/code/reason/snippet34.re new file mode 100644 index 000000000..31bd6d1a8 --- /dev/null +++ b/src/content/3.7/code/reason/snippet34.re @@ -0,0 +1 @@ +let unit = a => Reader(s => Prod(a, s)); diff --git a/src/content/3.7/code/reason/snippet35.re b/src/content/3.7/code/reason/snippet35.re new file mode 100644 index 000000000..52871bc9b --- /dev/null +++ b/src/content/3.7/code/reason/snippet35.re @@ -0,0 +1 @@ +let make_store = (f, s) => Store(f, s); diff --git a/src/content/3.7/code/reason/snippet36.re b/src/content/3.7/code/reason/snippet36.re new file mode 100644 index 000000000..3c59f86ad --- /dev/null +++ b/src/content/3.7/code/reason/snippet36.re @@ -0,0 +1 @@ +let duplicate = (Store(f, s)) => Store(make_store(f), s); diff --git a/src/content/3.7/code/reason/snippet37.re b/src/content/3.7/code/reason/snippet37.re new file mode 100644 index 000000000..f789f4e5a --- /dev/null +++ b/src/content/3.7/code/reason/snippet37.re @@ -0,0 +1,26 @@ +module StoreComonadBase = + (S: {type s;}, F: Functor with type t('a) = store(S.s, 'a)) + : (ComonadBase with type w('a) = store(S.s, 'a)) => { + type w('a) = store(S.s, 'a); + + include F; + + let extract = (Store(f, s)) => f(s); +}; + +module StoreComonadDuplicate = + (S: {type s;}) + : (ComonadDuplicate with type w('a) = store(S.s, 'a)) => { + type w('a) = store(S.s, 'a); + + let duplicate = (Store(f, s)) => Store(make_store(f), s); +}; + +/* Generate Full comonad */ +module StoreComonad = + (S: {type s;}, F: Functor with type t('a) = store(S.s, 'a)) + : (Comonad with type w('a) = store(S.s, 'a)) => + ComonadImplViaExtend( + (StoreComonadBase(S, F)), + (StoreComonadDuplicate(S)), + ); diff --git a/src/content/3.7/code/reason/snippet38.re b/src/content/3.7/code/reason/snippet38.re new file mode 100644 index 000000000..8fd5e8d6c --- /dev/null +++ b/src/content/3.7/code/reason/snippet38.re @@ -0,0 +1 @@ +'a => store('s, 'a); \ No newline at end of file diff --git a/src/content/3.7/code/reason/snippet39.re b/src/content/3.7/code/reason/snippet39.re new file mode 100644 index 000000000..d8e810a4d --- /dev/null +++ b/src/content/3.7/code/reason/snippet39.re @@ -0,0 +1,2 @@ +let get: 'a => 's; +let set: ('a, 's) => 'a; diff --git a/src/content/3.8/code/reason/snippet01.re b/src/content/3.8/code/reason/snippet01.re new file mode 100644 index 000000000..c7c996bbe --- /dev/null +++ b/src/content/3.8/code/reason/snippet01.re @@ -0,0 +1,2 @@ +module type Algebra = + (F: {type f('a);}) => {type algebra('a) = F.f('a) => 'a;}; diff --git a/src/content/3.8/code/reason/snippet02.re b/src/content/3.8/code/reason/snippet02.re new file mode 100644 index 000000000..83f2b810a --- /dev/null +++ b/src/content/3.8/code/reason/snippet02.re @@ -0,0 +1,3 @@ +type mon_f('a) = + | MEmpty + | Mappend(('a, 'a)); diff --git a/src/content/3.8/code/reason/snippet03.re b/src/content/3.8/code/reason/snippet03.re new file mode 100644 index 000000000..f874d6ca1 --- /dev/null +++ b/src/content/3.8/code/reason/snippet03.re @@ -0,0 +1,6 @@ +type ring_f('a) = + | RZero + | ROne + | RAdd(('a, 'a)) + | RMul(('a, 'a)) + | RNeg('a); diff --git a/src/content/3.8/code/reason/snippet04.re b/src/content/3.8/code/reason/snippet04.re new file mode 100644 index 000000000..c555bc33d --- /dev/null +++ b/src/content/3.8/code/reason/snippet04.re @@ -0,0 +1,12 @@ +module Ring = { + module RingAlg = Algebra({type f('a) = ring_f('a);}); + + let eval_z: RingAlg.algebra('a) = ( + fun + | RZero => 0 + | ROne => 1 + | RAdd(m, n) => m + n + | RMul(m, n) => m * n + | RNeg(n) => - n + ); +}; diff --git a/src/content/3.8/code/reason/snippet05.re b/src/content/3.8/code/reason/snippet05.re new file mode 100644 index 000000000..83c48583f --- /dev/null +++ b/src/content/3.8/code/reason/snippet05.re @@ -0,0 +1,6 @@ +type expr = + | RZero + | ROne + | RAdd((expr, expr)) + | RMul((expr, expr)) + | RNeg(expr); diff --git a/src/content/3.8/code/reason/snippet06.re b/src/content/3.8/code/reason/snippet06.re new file mode 100644 index 000000000..61adf14a3 --- /dev/null +++ b/src/content/3.8/code/reason/snippet06.re @@ -0,0 +1,8 @@ +let rec eval_z: expr => int = ( + fun + | RZero => 0 + | ROne => 1 + | RAdd(e1, e2) => eval_z(e1) + eval_z(e2) + | RMul(e1, e2) => eval_z(e1) * eval_z(e2) + | RNeg(e) => - eval_z(e) +); diff --git a/src/content/3.8/code/reason/snippet07.re b/src/content/3.8/code/reason/snippet07.re new file mode 100644 index 000000000..2a9a2196a --- /dev/null +++ b/src/content/3.8/code/reason/snippet07.re @@ -0,0 +1 @@ +type ring_f1('a) = ring_f(ring_f('a)); diff --git a/src/content/3.8/code/reason/snippet08.re b/src/content/3.8/code/reason/snippet08.re new file mode 100644 index 000000000..4eca37dd3 --- /dev/null +++ b/src/content/3.8/code/reason/snippet08.re @@ -0,0 +1 @@ +type ring_f2('a) = ring_f(ring_f(ring_f('a))); diff --git a/src/content/3.8/code/reason/snippet09.re b/src/content/3.8/code/reason/snippet09.re new file mode 100644 index 000000000..a9c36449d --- /dev/null +++ b/src/content/3.8/code/reason/snippet09.re @@ -0,0 +1 @@ +type ring_f2('a) = ring_f1(ring_f('a)); diff --git a/src/content/3.8/code/reason/snippet10.re b/src/content/3.8/code/reason/snippet10.re new file mode 100644 index 000000000..c6aef7a34 --- /dev/null +++ b/src/content/3.8/code/reason/snippet10.re @@ -0,0 +1,4 @@ +module Fix = (F: Functor) => { + type fix('a) = + | Fix(F.t(fix('a))); +}; diff --git a/src/content/3.8/code/reason/snippet11.re b/src/content/3.8/code/reason/snippet11.re new file mode 100644 index 000000000..2e3b727e0 --- /dev/null +++ b/src/content/3.8/code/reason/snippet11.re @@ -0,0 +1,4 @@ +module Fix = (F: Functor) => { + type fix('a) = + | In(F.t(fix('a))); +}; diff --git a/src/content/3.8/code/reason/snippet12.re b/src/content/3.8/code/reason/snippet12.re new file mode 100644 index 000000000..9befe0261 --- /dev/null +++ b/src/content/3.8/code/reason/snippet12.re @@ -0,0 +1,8 @@ +module Fix = (F: Functor) => { + type fix('a) = + | Fix(F.t(fix('a))); + + let fix: F.t(fix('a)) => fix('a) = ( + f => Fix(f): F.t(fix('a)) => fix('a) + ); +}; diff --git a/src/content/3.8/code/reason/snippet13.re b/src/content/3.8/code/reason/snippet13.re new file mode 100644 index 000000000..c00f4cb3a --- /dev/null +++ b/src/content/3.8/code/reason/snippet13.re @@ -0,0 +1,8 @@ +module Fix = (F: Functor) => { + type fix('a) = + | Fix(F.t(fix('a))); + + let unfix: fix('a) => F.t(fix('a)) = ( + (Fix(f)) => f: fix('a) => F.t(fix('a)) + ); +}; diff --git a/src/content/3.8/code/reason/snippet14.re b/src/content/3.8/code/reason/snippet14.re new file mode 100644 index 000000000..d2599735b --- /dev/null +++ b/src/content/3.8/code/reason/snippet14.re @@ -0,0 +1,3 @@ +type nat_f('a) = + | ZeroF + | SuccF('a); diff --git a/src/content/3.8/code/reason/snippet15.re b/src/content/3.8/code/reason/snippet15.re new file mode 100644 index 000000000..c65d4b4dd --- /dev/null +++ b/src/content/3.8/code/reason/snippet15.re @@ -0,0 +1,3 @@ +type nat = + | Zero + | Succ(nat); diff --git a/src/content/3.8/code/reason/snippet16.re b/src/content/3.8/code/reason/snippet16.re new file mode 100644 index 000000000..f6cd71e7b --- /dev/null +++ b/src/content/3.8/code/reason/snippet16.re @@ -0,0 +1,16 @@ +module Cata = (F: Functor) => { + type fix('a) = + | Fix(F.t(fix('a))); + + let fix: F.t(fix('a)) => fix('a) = ( + f => Fix(f): F.t(fix('a)) => fix('a) + ); + let unfix: fix('a) => F.t(fix('a)) = ( + (Fix(f)) => f: fix('a) => F.t(fix('a)) + ); + + let rec cata: (F.t('a) => 'a, fix('a)) => 'a = ( + (alg, fixf) => alg(F.fmap(cata(alg), unfix(fixf))): + (F.t('a) => 'a, fix('a)) => 'a + ); +}; diff --git a/src/content/3.8/code/reason/snippet17.re b/src/content/3.8/code/reason/snippet17.re new file mode 100644 index 000000000..d2599735b --- /dev/null +++ b/src/content/3.8/code/reason/snippet17.re @@ -0,0 +1,3 @@ +type nat_f('a) = + | ZeroF + | SuccF('a); diff --git a/src/content/3.8/code/reason/snippet18.re b/src/content/3.8/code/reason/snippet18.re new file mode 100644 index 000000000..76a153e97 --- /dev/null +++ b/src/content/3.8/code/reason/snippet18.re @@ -0,0 +1,4 @@ +let rec fib = + fun + | ZeroF => (1, 1) + | SuccF(m, n) => (n, m + n); diff --git a/src/content/3.8/code/reason/snippet19.re b/src/content/3.8/code/reason/snippet19.re new file mode 100644 index 000000000..c8deaeae0 --- /dev/null +++ b/src/content/3.8/code/reason/snippet19.re @@ -0,0 +1,3 @@ +type list_f('e, 'a) = + | NilF + | ConsF(('e, 'a)); diff --git a/src/content/3.8/code/reason/snippet20.re b/src/content/3.8/code/reason/snippet20.re new file mode 100644 index 000000000..e6ca2771c --- /dev/null +++ b/src/content/3.8/code/reason/snippet20.re @@ -0,0 +1,3 @@ +type list'('e) = + | Nil + | Cons(('e, list'('e))); diff --git a/src/content/3.8/code/reason/snippet21.re b/src/content/3.8/code/reason/snippet21.re new file mode 100644 index 000000000..c134772c0 --- /dev/null +++ b/src/content/3.8/code/reason/snippet21.re @@ -0,0 +1,4 @@ +let len_alg = + fun + | ConsF(e, n) => n + 1 + | NilF => 0; diff --git a/src/content/3.8/code/reason/snippet22.re b/src/content/3.8/code/reason/snippet22.re new file mode 100644 index 000000000..f81a49d82 --- /dev/null +++ b/src/content/3.8/code/reason/snippet22.re @@ -0,0 +1 @@ +let length = xs => List.fold_right((e, n) => n + 1, xs, 0); diff --git a/src/content/3.8/code/reason/snippet23.re b/src/content/3.8/code/reason/snippet23.re new file mode 100644 index 000000000..bc8b9c48b --- /dev/null +++ b/src/content/3.8/code/reason/snippet23.re @@ -0,0 +1,4 @@ +let sum_alg = + fun + | ConsF(e, s) => e +. s + | NilF => 0.0; diff --git a/src/content/3.8/code/reason/snippet24.re b/src/content/3.8/code/reason/snippet24.re new file mode 100644 index 000000000..a58519d0c --- /dev/null +++ b/src/content/3.8/code/reason/snippet24.re @@ -0,0 +1 @@ +let sum = xs => List.fold_right((e, s) => e +. s, xs, 0.0); diff --git a/src/content/3.8/code/reason/snippet25.re b/src/content/3.8/code/reason/snippet25.re new file mode 100644 index 000000000..6fa129bf3 --- /dev/null +++ b/src/content/3.8/code/reason/snippet25.re @@ -0,0 +1,9 @@ +module Ana = (F: Functor) => { + type fix('a) = + | Fix(F.t(fix('a))); + + let rec ana: ('a => F.t('a), 'a) => fix('a) = ( + (coalg, a) => Fix(F.fmap(ana(coalg), coalg(a))): + ('a => F.t('a), 'a) => fix('a) + ); +}; diff --git a/src/content/3.8/code/reason/snippet26.re b/src/content/3.8/code/reason/snippet26.re new file mode 100644 index 000000000..9b013891f --- /dev/null +++ b/src/content/3.8/code/reason/snippet26.re @@ -0,0 +1,11 @@ +type stream_f('e, 'a) = + | StreamF(('e, 'a)); + +module Stream_Functor = (E: {type e;}) : + (Functor with type t('a) = stream_f(E.e, 'a)) => { + type t('a) = stream_f(E.e, 'a); + + let fmap = f => + fun + | StreamF(e, a) => StreamF(e, f(a)); +}; diff --git a/src/content/3.8/code/reason/snippet27.re b/src/content/3.8/code/reason/snippet27.re new file mode 100644 index 000000000..f64cfeb15 --- /dev/null +++ b/src/content/3.8/code/reason/snippet27.re @@ -0,0 +1,2 @@ +type stream('e) = + | Stream(('e, stream('e))); diff --git a/src/content/3.8/code/reason/snippet28.re b/src/content/3.8/code/reason/snippet28.re new file mode 100644 index 000000000..6f6d76979 --- /dev/null +++ b/src/content/3.8/code/reason/snippet28.re @@ -0,0 +1,9 @@ +/* OCaml library `gen` provides useful helpers for + potentially infinite iterators. You can install it + with `opam install gen`. To use it in the toplevel, + you need to `#require "gen"` */ +let era: Gen.t(int) => stream_f(int, Gen.t(int)) = (ilist => { + let notdiv = (p, n) => n mod p !== 0; + let p = Gen.get_exn(ilist); + StreamF(p, Gen.filter(notdiv(p), ilist)); +}); \ No newline at end of file diff --git a/src/content/3.8/code/reason/snippet29.re b/src/content/3.8/code/reason/snippet29.re new file mode 100644 index 000000000..0cf51c09f --- /dev/null +++ b/src/content/3.8/code/reason/snippet29.re @@ -0,0 +1,8 @@ +module Stream_Int = Stream_Functor({type e = int;}); + +module Ana_Stream = Ana(Stream_Int); + +/* The fixpoint translated to ReasonML is eager in its evaluation. + Hence, executing the following function will cause overflow. + So, wrapping it inside a lazy */ +let primes = lazy(Ana_Stream.ana(era, Gen.init(i => i + 2))); diff --git a/src/content/3.8/code/reason/snippet30.re b/src/content/3.8/code/reason/snippet30.re new file mode 100644 index 000000000..3b1d9132f --- /dev/null +++ b/src/content/3.8/code/reason/snippet30.re @@ -0,0 +1,11 @@ +module List_C = (E: {type e;}) => { + module Stream_F: Functor with type t('a) = stream_f(E.e, 'a) = + Stream_Functor(E); + + module Cata_Stream = Cata(Stream_F); + + let to_list_c: Cata_Stream.fix(list(E.e)) => list(E.e) = ( + s_fix => Cata_Stream.cata((StreamF(e, a)) => [e, ...a], s_fix): + Cata_Stream.fix(list(E.e)) => list(E.e) + ); +}; diff --git a/src/content/3.8/code/reason/snippet31.re b/src/content/3.8/code/reason/snippet31.re new file mode 100644 index 000000000..7eae382d8 --- /dev/null +++ b/src/content/3.8/code/reason/snippet31.re @@ -0,0 +1,3 @@ +/* Gen.t is used to represent infinite data structures + like haskell's lazy list */ +let unfold: ('b => option(('a, 'b)), 'b) => Gen.t('a); diff --git a/src/content/3.8/code/reason/snippet32.re b/src/content/3.8/code/reason/snippet32.re new file mode 100644 index 000000000..baac4300d --- /dev/null +++ b/src/content/3.8/code/reason/snippet32.re @@ -0,0 +1,2 @@ +let set: ('a, 's) => 'a; +let get: 'a => 's; diff --git a/src/content/3.8/code/reason/snippet33.re b/src/content/3.8/code/reason/snippet33.re new file mode 100644 index 000000000..7db46d7dc --- /dev/null +++ b/src/content/3.8/code/reason/snippet33.re @@ -0,0 +1 @@ +(a, (s, s => a)); \ No newline at end of file diff --git a/src/content/3.8/code/reason/snippet34.re b/src/content/3.8/code/reason/snippet34.re new file mode 100644 index 000000000..8fd5e8d6c --- /dev/null +++ b/src/content/3.8/code/reason/snippet34.re @@ -0,0 +1 @@ +'a => store('s, 'a); \ No newline at end of file diff --git a/src/content/3.8/code/reason/snippet35.re b/src/content/3.8/code/reason/snippet35.re new file mode 100644 index 000000000..52c67c530 --- /dev/null +++ b/src/content/3.8/code/reason/snippet35.re @@ -0,0 +1,3 @@ +/* Store is the comonad version of State */ +type store('s, 'a) = + | Store('s => 'a, 's); diff --git a/src/content/3.9/code/reason/snippet01.re b/src/content/3.9/code/reason/snippet01.re new file mode 100644 index 000000000..dbf892dbc --- /dev/null +++ b/src/content/3.9/code/reason/snippet01.re @@ -0,0 +1 @@ +compose(alg, return) == id(compose, alg, join) == compose(alg, fmap(alg)); diff --git a/src/content/3.9/code/reason/snippet02.re b/src/content/3.9/code/reason/snippet02.re new file mode 100644 index 000000000..66adac863 --- /dev/null +++ b/src/content/3.9/code/reason/snippet02.re @@ -0,0 +1 @@ +let fold_right: (('a, 'b) => 'b, list('a), 'b) => 'b; diff --git a/src/content/3.9/code/reason/snippet03.re b/src/content/3.9/code/reason/snippet03.re new file mode 100644 index 000000000..243cd64fc --- /dev/null +++ b/src/content/3.9/code/reason/snippet03.re @@ -0,0 +1,2 @@ +/* List module in the OCaml standard library accepts list before z */ +List.fold_right(f, [x], z) == f(x, z); diff --git a/src/content/3.9/code/reason/snippet04.re b/src/content/3.9/code/reason/snippet04.re new file mode 100644 index 000000000..b072c38ae --- /dev/null +++ b/src/content/3.9/code/reason/snippet04.re @@ -0,0 +1 @@ +f(x, z) == x; diff --git a/src/content/3.9/code/reason/snippet05.re b/src/content/3.9/code/reason/snippet05.re new file mode 100644 index 000000000..fc27adc2a --- /dev/null +++ b/src/content/3.9/code/reason/snippet05.re @@ -0,0 +1,3 @@ +module Kleisli_Composition = (T: MonadJoin) => { + let h = (g, f) => T.join <.> T.fmap(g) <.> f; +}; diff --git a/src/content/3.9/code/reason/snippet06.re b/src/content/3.9/code/reason/snippet06.re new file mode 100644 index 000000000..c50450a5a --- /dev/null +++ b/src/content/3.9/code/reason/snippet06.re @@ -0,0 +1,3 @@ +module C_to_CT = (T: Monad) => { + let on_objects = T.return <.> f; +}; diff --git a/src/content/3.9/code/reason/snippet07.re b/src/content/3.9/code/reason/snippet07.re new file mode 100644 index 000000000..086ae3c5a --- /dev/null +++ b/src/content/3.9/code/reason/snippet07.re @@ -0,0 +1,2 @@ +type store('s, 'a) = + | Store('s => 'a, 's); diff --git a/src/content/3.9/code/reason/snippet08.re b/src/content/3.9/code/reason/snippet08.re new file mode 100644 index 000000000..68bd01819 --- /dev/null +++ b/src/content/3.9/code/reason/snippet08.re @@ -0,0 +1,13 @@ +module Store_comonad = + (S: {type s;}, F: Functor with type t('a) = store(S.s, 'a)) + : (Comonad with type w('a) = store(S.s, 'a)) => { + type w('a) = store(S.s, 'a); + + include F; + + let extract: w('a) => 'a = ((Store(f, s)) => f(s): w('a) => 'a); + + let duplicate: w('a) => w(w('a)) = ( + (Store(f, s)) => Store(s => Store(f, s), s): w('a) => w(w('a)) + ); +}; diff --git a/src/content/3.9/code/reason/snippet09.re b/src/content/3.9/code/reason/snippet09.re new file mode 100644 index 000000000..e7f1e1c45 --- /dev/null +++ b/src/content/3.9/code/reason/snippet09.re @@ -0,0 +1,7 @@ +module Store_Functor = (S: {type s;}) : + (Functor with type t('a) = store(S.s, 'a)) => { + type w('a) = store(S.s, 'a); + type t('a) = w('a); + + let fmap = (g, Store(f, s)) => Store(compose(g, f), s); +}; diff --git a/src/content/3.9/code/reason/snippet10.re b/src/content/3.9/code/reason/snippet10.re new file mode 100644 index 000000000..754c782fb --- /dev/null +++ b/src/content/3.9/code/reason/snippet10.re @@ -0,0 +1,3 @@ +/* Assume <.> acts as compose */ + +Store(coalg_store <.> set(a), get(a)); diff --git a/src/content/3.9/code/reason/snippet11.re b/src/content/3.9/code/reason/snippet11.re new file mode 100644 index 000000000..6f272e157 --- /dev/null +++ b/src/content/3.9/code/reason/snippet11.re @@ -0,0 +1 @@ +Store(s => Store(set(a), s), get(a)); diff --git a/src/content/3.9/code/reason/snippet12.re b/src/content/3.9/code/reason/snippet12.re new file mode 100644 index 000000000..9034784d3 --- /dev/null +++ b/src/content/3.9/code/reason/snippet12.re @@ -0,0 +1,2 @@ +/* Pseudo ReasonML */ +let coalg_store = (set, a, s) => Store((set(a)), s) diff --git a/src/content/3.9/code/reason/snippet13.re b/src/content/3.9/code/reason/snippet13.re new file mode 100644 index 000000000..8ed3108e4 --- /dev/null +++ b/src/content/3.9/code/reason/snippet13.re @@ -0,0 +1,3 @@ +/* Expaning coalg_store */ + +Store(set(set(a, s)), get(set(a, s))) == Store(set(a), s); diff --git a/src/content/3.9/code/reason/snippet14.re b/src/content/3.9/code/reason/snippet14.re new file mode 100644 index 000000000..a979dd6ea --- /dev/null +++ b/src/content/3.9/code/reason/snippet14.re @@ -0,0 +1 @@ +set(set(a, s)) == set(a); diff --git a/src/content/3.9/code/reason/snippet15.re b/src/content/3.9/code/reason/snippet15.re new file mode 100644 index 000000000..04976ae98 --- /dev/null +++ b/src/content/3.9/code/reason/snippet15.re @@ -0,0 +1 @@ +get(set(a, s)) == s; diff --git a/src/content/reason/colophon.tex b/src/content/reason/colophon.tex new file mode 100644 index 000000000..9b131c9bd --- /dev/null +++ b/src/content/reason/colophon.tex @@ -0,0 +1 @@ +ReasonML code translation was done by \urlref{https://github.com/fhammerschmidt/}{Florian Hammerschmidt}. \ No newline at end of file diff --git a/src/content/reason/editor-note.tex b/src/content/reason/editor-note.tex new file mode 100644 index 000000000..9a13bccbb --- /dev/null +++ b/src/content/reason/editor-note.tex @@ -0,0 +1,27 @@ +% !TEX root = ctfp-print.tex + +\lettrine[lhang=0.17]{T}{his is the} ReasonML edition of \emph{Category Theory for Programmers}. +It's been a tremendous success, making Bartosz Milewski's blog post series available as a nicely- +typeset \acronym{PDF}, as well as a hardcover book. There have been numerous contributions made +to improve the book, by fixing typos and errors, as well as translating the code snippets into +other programming languages. + +I am thrilled to present this edition of the book, containing the original Haskell code, followed by +its ReasonML counterpart. The ReasonML code snippets were converted from the OCaml snippets which were +generously provided by \urlref{https://github.com/ArulselvanMadhavan/ocaml-ctfp}{ocaml-ctfp} contributors, +and slightly modified to suit the format of this book. + +To support code snippets in multiple languages, I am using a \LaTeX{} macro to load the code snippets +from external files. This allows easily extending the book with other languages, while leaving the +original text intact. Which is why you should mentally append the words ``and ReasonML'' whenever you see +``in Haskell'' in the text. + +The code is laid out in the following manner: the original Haskell code, followed by ReasonML code. +To distinguish between them, the code snippets are braced from the left with a vertical bar, in the primary +color of the language's logo, \raisebox{-.2mm}{\includegraphics[height=.3cm]{fig/icons/haskell.png}}, +and \raisebox{-.2mm}{\includegraphics[height=.3cm]{fig/icons/reason.png}} respectively, e.g.: + +\srcsnippet{content/1.1/code/haskell/snippet03.hs}{blue}{haskell} +\unskip +\srcsnippet{content/1.1/code/reason/snippet03.re}{RedOrange}{reason} +\NoIndentAfterThis \ No newline at end of file diff --git a/src/cover/cover-hardcover-reason.tex b/src/cover/cover-hardcover-reason.tex new file mode 100644 index 000000000..ae049ae45 --- /dev/null +++ b/src/cover/cover-hardcover-reason.tex @@ -0,0 +1,117 @@ +\documentclass[ + coverheight=9.249in, + coverwidth=6.319in, % (pagesize - spinewidth) / 2 + spinewidth=1.125in, + bleedwidth=0.306in, + 11pt, + marklength=0pt, + ]{bookcover} + + \usepackage{fancybox} + \usepackage{wrapfig} + \usepackage[many]{tcolorbox} + \usetikzlibrary{calc,positioning, shadings} + \usepackage[T1]{fontenc} + \usepackage{fontspec} + + \setmainfont[ + Path=fonts/, + Extension=.otf, + UprightFont=*-Regular, + ItalicFont=*-Italic, + BoldFont=*-Bold, + UprightFeatures={SmallCapsFont=*SC-Regular}, + ItalicFeatures={SmallCapsFont=*SC-Italic}, + BoldFeatures={SmallCapsFont=*SC-Bold}, + BoldItalicFeatures={SmallCapsFont=*SC-BoldItalic}, + ]{AlegreyaSans} + + \newcommand{\olpath}{../} + \newcommand{\whitebg}[1]{% + \tikz\node[circle,draw,minimum size=1.1cm, + fill=white, + path picture={ + \node at (path picture bounding box){ + \includegraphics[width=1.1cm]{\olpath#1} + }; + }]{}; + } + \newcommand{\bartosz}{ + \vspace{0pt} + \begin{tcolorbox}[beamer, + width=3.6cm, + arc=0pt, + boxsep=0pt, + left=0pt,right=0pt,top=0pt,bottom=0pt, + ] \includegraphics[width=3.6cm]{bartosz} + \end{tcolorbox} + } + \input{\olpath/version} + + \definecolor{BackgroundColor}{HTML}{f3f6ed} + \definecolor{SpineBackColor}{HTML}{262626} + + \begin{document} + + \begin{bookcover} + \bookcovercomponent{color}{bg whole}{color=BackgroundColor} + \bookcovercomponent{color}{spine}{color=SpineBackColor} + \bookcovercomponent{normal}{front}{ + \input{ribbon-reason} + \vspace{1.1cm} + \begin{center} + \fontsize{40pt}{5em}\selectfont\bfseries + CATEGORY THEORY \\FOR PROGRAMMERS + \vfil + \hspace*{-.8cm}\includegraphics[width=.5\coverwidth]{piggie} + \linebreak + \rule[1.5cm]{\textwidth/2}{.5pt}\\ + \vspace{-1.5cm} + \normalfont\Huge\textbf{Bartosz Milewski} + \vfil + \vspace*{1cm} + \end{center}} + + \bookcovercomponent{center}{spine}{ + \rotatebox[origin=c]{-90}{\color{orange} + \Huge\bfseries Category Theory for Programmers \hspace{2em} Bartosz Milewski}} + + \bookcovercomponent{normal}{back}{% + \begin{minipage}[b][\coverheight][t]{\coverwidth} + \begin{center} + \vspace{1cm} + \includegraphics[width=.8\coverwidth]{bunnies} + \begin{minipage}[t]{.8\coverwidth} + \input{blurb} + \vspace{.5cm} + \end{minipage} + + \begin{minipage}{.85\textwidth} + \rule{\textwidth}{.5pt} + + \begin{tabular}[h]{p{3.4cm} p{\textwidth}} + \bartosz + & + \vspace{5pt} + \begin{minipage}[b]{.58\coverwidth} + \fontsize{11pt}{1.4em}\selectfont\textit{Category Theory for Programmers} + is a series of blog posts by Bartosz Milewski, originally posted on bartoszmilewski.com.\\ + Edited by Igal Tabachnik. Licenced under CC BY-SA 4.0.\\ + \end{minipage} + \end{tabular} + \begin{flushright} + \vspace{-2.6cm} + \begin{minipage}[b]{4cm} + \raggedleft + \whitebg{fig/icons/by} + \whitebg{fig/icons/cc} + \whitebg{fig/icons/sa} + \centering\footnotesize{\texttt{\OPTversion}} + \end{minipage} + \end{flushright} + \end{minipage} + \end{center} + \end{minipage} + } + \end{bookcover} +\end{document} \ No newline at end of file diff --git a/src/cover/cover-paperback-reason.tex b/src/cover/cover-paperback-reason.tex new file mode 100644 index 000000000..e496f83f6 --- /dev/null +++ b/src/cover/cover-paperback-reason.tex @@ -0,0 +1,127 @@ +\documentclass[ + % bleed is added to the final result + coverheight=9.25in, + coverwidth=6.125in, % (pagesize - spinewidth) / 2 == (13.042 - 1.042) / 2 + spinewidth=1.042in, + bleedwidth=0in, + 11pt, + marklength=0in, + ]{bookcover} + + \usepackage{fancybox} + \usepackage{wrapfig} + \usepackage[many]{tcolorbox} + \usetikzlibrary{calc,positioning, shadings} + \usepackage[T1]{fontenc} + \usepackage{fontspec} + + % \setmainfont{AlegreyaSans-Regular}[ + % BoldFont={AlegreyaSans-Bold}, + % ItalicFont={AlegreyaSans-Italic}, + % UprightFeatures={SmallCapsFont=AlegreyaSansSC-Regular}, + % ItalicFeatures={SmallCapsFont=AlegreyaSansSC-Italic}, + % BoldFeatures={SmallCapsFont=AlegreyaSansSC-Bold}, + % BoldItalicFeatures={SmallCapsFont=AlegreyaSansSC-BoldItalic}, + % ] + \setmainfont[ + Path=fonts/, + Extension=.otf, + UprightFont=*-Regular, + ItalicFont=*-Italic, + BoldFont=*-Bold, + UprightFeatures={SmallCapsFont=*SC-Regular}, + ItalicFeatures={SmallCapsFont=*SC-Italic}, + BoldFeatures={SmallCapsFont=*SC-Bold}, + BoldItalicFeatures={SmallCapsFont=*SC-BoldItalic}, + ]{AlegreyaSans} + + \newcommand{\olpath}{../} + \newcommand{\whitebg}[1]{% + \tikz\node[circle,draw,minimum size=1.1cm, + fill=white, + path picture={ + \node at (path picture bounding box){ + \includegraphics[width=1.1cm]{\olpath#1} + }; + }]{}; + } + \newcommand{\bartosz}{ + \vspace{0pt} + \begin{tcolorbox}[beamer, + width=3.6cm, + arc=0pt, + boxsep=0pt, + left=0pt,right=0pt,top=0pt,bottom=0pt, + ] \includegraphics[width=3.6cm]{bartosz} + \end{tcolorbox} + } + \input{\olpath/version} + + \definecolor{BackgroundColor}{HTML}{f3f6ed} + \definecolor{SpineBackColor}{HTML}{262626} + + \begin{document} + + \begin{bookcover} + \bookcovercomponent{color}{bg whole}{color=BackgroundColor} + \bookcovercomponent{color}{spine}{color=SpineBackColor} + \bookcovercomponent{normal}{front}{ + \input{ribbon-reason} + \vspace{1.1cm} + \begin{center} + \fontsize{40pt}{5em}\selectfont\bfseries + CATEGORY THEORY \\FOR PROGRAMMERS + \vfil + \hspace*{-.8cm}\includegraphics[width=.5\coverwidth]{piggie} + \linebreak + \rule[1.5cm]{\textwidth/2}{.5pt}\\ + \vspace{-1.5cm} + \normalfont\Huge\textbf{Bartosz Milewski} + \vfil + \vspace*{1cm} + \end{center}} + + \bookcovercomponent{center}{spine}{ + \rotatebox[origin=c]{-90}{\color{orange} + \Huge\bfseries Category Theory for Programmers \hspace{2em} Bartosz Milewski}} + + \bookcovercomponent{normal}{back}{% + \begin{minipage}[b][\coverheight][t]{\coverwidth} + \begin{center} + \vspace{1cm} + \includegraphics[width=.8\coverwidth]{bunnies} + \begin{minipage}[t]{.75\coverwidth} + \input{blurb} + \vspace{0.6cm} + \end{minipage} + + \begin{minipage}{.85\textwidth} + \rule{\textwidth}{.5pt} + + \begin{tabular}[h]{p{3.4cm} p{\textwidth}} + \vspace{5pt} + \bartosz + & + \vspace{10pt} + \begin{minipage}[b]{.58\coverwidth} + \fontsize{11pt}{1.4em}\selectfont\textit{Category Theory for Programmers} + is a series of blog posts by Bartosz Milewski, originally posted on bartoszmilewski.com.\\ + Edited by Igal Tabachnik. Licenced under CC BY-SA 4.0.\\ + \end{minipage} + \end{tabular} + \begin{flushright} + \vspace{-2.6cm} + \begin{minipage}[b]{4cm} + \raggedleft + \whitebg{fig/icons/by} + \whitebg{fig/icons/cc} + \whitebg{fig/icons/sa} + \centering\footnotesize{\texttt{\OPTversion}} + \end{minipage} + \end{flushright} + \end{minipage} + \end{center} + \end{minipage} + } + \end{bookcover} +\end{document} \ No newline at end of file diff --git a/src/cover/ribbon-ocaml.tex b/src/cover/ribbon-ocaml.tex index 244d2ce62..ff1a25a65 100644 --- a/src/cover/ribbon-ocaml.tex +++ b/src/cover/ribbon-ocaml.tex @@ -17,7 +17,7 @@ \coordinate (B) at ($ (current page.south east) + (0,\stripskip) $);% <-- changed coordinate from 'north' to south' and sign for \stripskip \coordinate (B') at ($(B) + (0,\stripwidth) $);% <-- changed sign for \stripskip - \fill [BurntOrange!20] (A) -- (A') -- (B') -- (B) -- cycle; + \fill [RedOrange!20] (A) -- (A') -- (B') -- (B) -- cycle; \coordinate (tempA) at ($(A)!.5!(A')$); \coordinate (tempB) at ($(B)!.5!(B')$); diff --git a/src/cover/ribbon-reason.tex b/src/cover/ribbon-reason.tex new file mode 100644 index 000000000..25cacc413 --- /dev/null +++ b/src/cover/ribbon-reason.tex @@ -0,0 +1,30 @@ +% !TeX root = ./cover-paperback-reason.tex + +\newcommand{\stripskip}{4} +\newcommand{\stripwidth}{3} + +\definecolor{RedOrange}{rgb}{0.8, 0.33, 0.0} + +\begin{tikzpicture}[ + overlay, + remember picture, + ribbon/.style={anchor=center, rotate = 45, + font={\fontsize{22}{1}\selectfont\bfseries}} + ] + \coordinate (A) at ($ (current page.south east) + (-\stripskip,0) $);% <-- changed coordinate from 'north' to south' + \coordinate (A') at ($(A) + (-\stripwidth,0) $); + + \coordinate (B) at ($ (current page.south east) + (0,\stripskip) $);% <-- changed coordinate from 'north' to south' and sign for \stripskip + \coordinate (B') at ($(B) + (0,\stripwidth) $);% <-- changed sign for \stripskip + + \fill [RedOrange!20] (A) -- (A') -- (B') -- (B) -- cycle; + + \coordinate (tempA) at ($(A)!.5!(A')$); + \coordinate (tempB) at ($(B)!.5!(B')$); + + \node [ribbon](text) at ($(tempA)!.5!(tempB)$) { + \raisebox{-.15\height}{\includegraphics[width=.8cm]{\olpath/fig/icons/reason}} + \hspace{.5mm} ReasonML Edition + }; + +\end{tikzpicture} \ No newline at end of file diff --git a/src/ctfp-print-reason.tex b/src/ctfp-print-reason.tex new file mode 100644 index 000000000..0b7df6be9 --- /dev/null +++ b/src/ctfp-print-reason.tex @@ -0,0 +1,3 @@ +\input{opt-reason} +\input{ctfp-print} +\input{postamble} \ No newline at end of file diff --git a/src/ctfp-reader-reason.tex b/src/ctfp-reader-reason.tex new file mode 100644 index 000000000..177071cb2 --- /dev/null +++ b/src/ctfp-reader-reason.tex @@ -0,0 +1,3 @@ +\input{opt-reason} +\input{ctfp-reader} +\input{postamble} \ No newline at end of file diff --git a/src/fig/icons/reason.png b/src/fig/icons/reason.png new file mode 100644 index 000000000..050be6816 Binary files /dev/null and b/src/fig/icons/reason.png differ diff --git a/src/opt-reason.tex b/src/opt-reason.tex new file mode 100644 index 000000000..64bc2dbcc --- /dev/null +++ b/src/opt-reason.tex @@ -0,0 +1,4 @@ +\def\OPTCustomLanguage{reason} +\def\OPTCustomLanguageExt{re} +\def\OPTCustomLanguageColor{RedOrange} +\def\OPTDisplayLanguageName{ReasonML} \ No newline at end of file