-
Notifications
You must be signed in to change notification settings - Fork 601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make OCaml code samples closer to Haskell (chapters 1 to 4) #242
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1 @@ | ||
module type Polymorphic_Function_F = sig | ||
type a | ||
type b | ||
|
||
val f : a -> b | ||
end | ||
val f : a -> b |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1 @@ | ||
module type Polymorphic_Function_G = sig | ||
type b | ||
type c | ||
|
||
val g : b -> c | ||
end | ||
val g : b -> c |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,3 @@ | ||
module Compose_Example | ||
(F : Polymorphic_Function_F) | ||
(G : Polymorphic_Function_G with type b = F.b) = | ||
struct | ||
(** OCaml doesn't have a compose operator. So, creating one. **) | ||
let ( >> ) g f x = g (f x) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was confusing because earlier F#'s chevron operator was mentioned which is the same There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok so I've read earlier issues that explain why it was this verbose. interesting POVs. |
||
|
||
let compose : 'a -> 'c = G.g >> F.f | ||
end | ||
(** OCaml doesn't have a compose operator. So, creating one. **) | ||
let ( % ) g f x = g (f x) | ||
g % f |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,5 @@ | ||
module Compose_Three_GF = functor(F:Polymorphic_Function_F)(G:Polymorphic_Function_G with type b = F.b)(H:Polymorphic_Function_H with type c = G.c) -> struct | ||
let compose : 'a -> 'd = H.h >> (G.g >> F.f) | ||
end | ||
val f : a -> b | ||
val g : b -> c | ||
val h : c -> d | ||
|
||
module Compose_Three_HG = functor(F:Polymorphic_Function_F)(G:Polymorphic_Function_G with type b = F.b)(H:Polymorphic_Function_H with type c = G.c) -> struct | ||
let compose : 'a -> 'd = (H.h >> G.g) >> F.f | ||
end | ||
|
||
Compose_Three_GF.compose = Compose_Three_HG.compose | ||
h % (g % f) = (h % g) % f = h % g % f |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
f >> id | ||
id >> f | ||
f % id = f | ||
id % f = f |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
module type Chapter2_DeclareVariable = sig | ||
val x : int | ||
end | ||
val x : int |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
module type Chapter2_DeclareFunction = sig | ||
val f : bool -> bool | ||
end | ||
val f : bool -> bool |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
module Chapter2_Bottom : Chapter2_DeclareFunction = struct | ||
let f (b : bool) : bool = failwith "Not Implemented" | ||
end | ||
(* val f : bool -> bool *) | ||
let f _x = failwith "Not Implemented" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
module Chapter2_Bottom : Chapter2_DeclareFunction = struct | ||
let f : bool -> bool = fun _ -> failwith "Not implemented" | ||
end | ||
(* val f : bool -> bool *) | ||
let f = failwith "Not Implemented" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,14 @@ | ||
let fact n = List.fold (List.range 1 n) ~init:1 ~f:( * ) | ||
(* OCaml doesn't ship with a lazy sequence range syntax nor a product | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 I think I used Janestreet libs in a few places to reduce the snippet size and to move ahead quickly, but thanks for removing the dependency! |
||
function; defining our own. *) | ||
|
||
let rec range seq n1 n2 = | ||
if n2 < n1 then seq | ||
else n2 |> pred |> range (fun () -> Seq.Cons (n2, seq)) n1 | ||
let range = range Seq.empty | ||
|
||
let rec product result seq = match seq () with | ||
| Seq.Nil -> result | ||
| Seq.Cons (n, seq) -> product (result * n) seq | ||
let product = product 1 | ||
|
||
let fact n = product (range 1 n) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not just let factorial n = Seq.fold_left ( * ) 1 (Seq.init n succ) or let product = Seq.fold_left ( * ) 1
let factorial n = Seq.init n succ |> product or use |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
type void | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. type void = | or just use the word |
||
|
||
let rec absurd (x : void) = absurd x | ||
val absurd : void -> 'a |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
let f44 () : int = 44 | ||
(* val f44 : unit -> int *) | ||
let f44 () = 44 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
let f_int (x : int) = () | ||
(* val f_int : int -> unit *) | ||
let f_int x = () |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
let f_int (_ : int) = () | ||
(* val f_int :: int -> unit *) | ||
let f_int _ = () |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
(* val unit : 'a -> unit *) | ||
let unit _ = () |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
module type Monoid = sig | ||
type a | ||
module type MONOID = sig | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it an OCaml convention to capitalize the module type? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi yes I believe so, e.g. see http://www.mseri.me/typeclass-ocaml/
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the convention originates from SML, it's loosely followed in OCaml really (even stdlib doesn't follow it). |
||
type t | ||
|
||
val mempty : a | ||
val mappend : a -> a -> a | ||
val mempty : t | ||
val mappend : t -> t -> t | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
module StringMonoid : Monoid = struct | ||
type a = string | ||
(* In OCaml, any module that defines a module type's members, | ||
automatically conforms to that module type. It doesn't need to | ||
explicitly declare that it conforms. *) | ||
|
||
let mempty = "" | ||
let mappend = ( ^ ) | ||
end | ||
type t = string | ||
|
||
let mempty = "" | ||
let mappend = ( ^ ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1 @@ | ||
module type Kleisli = sig | ||
type a | ||
type b | ||
type c | ||
|
||
val ( >=> ) : (a -> b writer) -> (b -> c writer) -> a -> c writer | ||
end | ||
val ( >=> ) : ('a -> 'b writer) -> ('b -> 'c writer) -> 'a -> 'c writer |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
let pure x = x, "" | ||
let ( >=> ) m1 m2 = fun x -> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The snippets are starting to diverge here but I hope they are in the right place in the book There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, the best way would probably be to run the LaTeX compilation and check the output, but from reading along the chapter I believe the sequence of the code samples now makes sense. |
||
let y, s1 = m1 x in | ||
let z, s2 = m2 y in | ||
z, s1 ^ s2 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
let up_case : string -> string writer = | ||
fun s -> String.uppercase s, "up_case " | ||
;; | ||
(* val return : 'a -> 'a writer *) | ||
let return x = x, "" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
let to_words : string -> string list writer = | ||
fun s -> String.split s ~on:' ', "to_words " | ||
;; | ||
(* val up_case : string -> string writer | ||
Note: OCaml strings are raw bytestrings, not UTF-8 encoded. *) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The book never mentions UTF-8 encoding.. Maybe this makes sense in an OCaml tutorial to note, but why here? |
||
let up_case s = String.uppercase_ascii s, "up_case " | ||
|
||
(* val to_words : string -> string list writer *) | ||
let to_words s = String.split_on_char ' ' s, "to_words " |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,2 @@ | ||
module KleisiExample | ||
(K : Kleisli | ||
with type a = string | ||
and type b = string | ||
and type c = string list) = | ||
struct | ||
let up_case_and_to_words : string -> string list writer = | ||
K.( >=> ) up_case to_words | ||
;; | ||
end | ||
(* val process : string -> string list writer *) | ||
let process = up_case >=> to_words |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was definitely confusing for me when I started going through the ocaml book (as an ocaml beginner when I saw these modules). 👍