-
Notifications
You must be signed in to change notification settings - Fork 598
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
Update OCaml snippets #346
base: master
Are you sure you want to change the base?
Changes from all commits
5200e2d
d26f52f
5c25300
b29fc3a
b00e4a8
a6a55fd
c2f09b4
db3f2cb
d40a2b3
7ab3ab4
c3cf7c2
949a898
cd63d30
651fa48
d4c9580
b1be757
d0d829c
ba65eed
56f05f0
16d42e6
35d132e
3db8b2b
9d56fe8
33e0b25
cca3f37
3663638
837676c
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 (* In a module signature *) |
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 (* In a module signature *) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,7 @@ | ||
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) | ||
Fun.compose g f (* Since OCaml 5.2 *) | ||
|
||
let compose : 'a -> 'c = G.g >> F.f | ||
end | ||
(* Alternatively, you can also define it as follows: *) | ||
let compose f g x = f (g x) | ||
|
||
(* Or even as an infix operator: *) | ||
let ( % ) = Fun.compose (* Like in the Batteries library *) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,6 @@ | ||
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 | ||
|
||
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 | ||
(* Assuming these signatures *) | ||
val f : a -> b | ||
val g : b -> c | ||
val h : c -> d | ||
(* These are equivalent *) | ||
h % (g % f) = (h % g) % f = h % g % f |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
let id x = x | ||
(* val id : 'a -> 'a *) | ||
let id x = x (* Also defined as Fun.id in the Stdlib *) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
f >> id | ||
id >> f | ||
f % Fun.id = f | ||
Fun.id % f = f |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
val alpha : 'a . 'a f -> 'a g | ||
val alpha : 'a . 'a F.t -> 'a G.t (* For 2 Functors F and G *) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
val alpha : 'a f -> 'a g | ||
val alpha : 'a F.t -> 'a G.t (* For 2 Functors F and G *) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
val alpha : 'a f -> 'a g | ||
val alpha : 'a F.t -> 'a G.t |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
let safe_head = function | ||
| [] -> None | ||
| x :: xs -> Some x | ||
;; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
compose (fmap f) safe_head = compose safe_head (fmap f) | ||
(* Given a Functor implementation for Option and List, | ||
the following equality should hold: *) | ||
OptionFunctor.fmap f % safe_head = safe_head % ListFunctor.fmap f | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
(* Starting with empty list *) | ||
let fmap f (safe_head []) = fmap f None = None | ||
(* As a reminder, this is not actual code *) | ||
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. To clarify, I would say something like: 'As a reminder, this is not actual OCaml code, it is a demonstration of equational reasoning'. 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. Honestly, there are a lot of snippets that aren't really code (just basically equations) and the Haskell version would suffice in those cases. Maybe these could be removed instead of duplicating the equational reasoning? |
||
OptionFunctor.fmap f (safe_head []) | ||
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. Same comment as above for the use of the |
||
= OptionFunctor.fmap f None | ||
= None |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
let safe_head (fmap f []) = safe_head [] = None | ||
safe_head (ListFunctor.fmap f []) = safe_head [] = None |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
let fmap f (safe_head (x :: xs)) = fmap f (Some x)= Some (f x) | ||
OptFunctor.fmap f (safe_head (x :: xs)) | ||
= OptFunctor.fmap f (Some x) | ||
= Some (f x) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
let safe_head (fmap f (x :: xs)) = safe_head (f x :: f xs) = Some (f x) | ||
|
||
safe_head (ListFunctor.fmap f (x :: xs)) | ||
= safe_head (f x :: f xs) | ||
= Some (f x) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
let rec fmap f = function | ||
| [] -> [] | ||
| x :: xs -> f x :: fmap f xs | ||
;; | ||
module ListFunctor : Functor with type 'a t = 'a list = struct | ||
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. Imho, OCaml will derive this type without any annotation just like in Haskell. We could just show the implementation ie: (* list.ml *)
type 'a t = 'a list = ...
let rec map = function ... And this would be enough to fulfill a 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 type annotation was just so the reader can be sure that the module If we made the previous snippets use the |
||
type 'a t = 'a list | ||
let rec fmap f = function | ||
| [] -> [] | ||
| x :: xs -> f x :: fmap f xs | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,14 @@ | ||
let rec fmap f = function | ||
| None -> None | ||
| Some x -> Some (f x) | ||
;; | ||
module OptionFunctor : Functor with type 'a t = 'a option = struct | ||
type 'a t = 'a option | ||
|
||
let fmap f = function | ||
| None -> None | ||
| Some x -> Some (f x) | ||
end | ||
|
||
(* As a reminder, note that in the OCaml Stdlib, the List | ||
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. Ah, I see you mentioned this; I would recommend just showing the implementations as they would be in the standard library instead of trying to implement 'instances' as micro modules and the |
||
and Option modules are already "Functors" in the sense | ||
that they have an fmap function (called map). Thus, the | ||
following fmaps do the same as the fmaps defined above. *) | ||
let option_fmap f = Option.map f | ||
let list_fmap f = List.map f |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,6 @@ | ||
(** OCaml requires mutually recursive functions to be defined together *) | ||
type ('c, 'a) const = Const of 'c | ||
|
||
(* Assuming you've defined un_const before this function *) | ||
let rec length : 'a list -> (int, 'a) const = function | ||
| [] -> Const 0 | ||
| _ :: xs -> Const (1 + un_const (length xs)) | ||
|
||
and un_const : 'c 'a. ('c, 'a) const -> 'c = function | ||
| Const c -> c | ||
;; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
let un_const : 'c 'a. ('c, 'a) const -> 'c = function | ||
| Const c -> c | ||
;; | ||
let un_const (Const c) = c |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
let scam : 'a. ('int, 'a) const -> 'a option = function | ||
| Const a -> None | ||
;; | ||
let scam (Const x : (int, 'a) const) : 'a option = None |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,7 @@ | ||
module Reader_Functor (T : sig | ||
type e | ||
end) : Functor = struct | ||
end) : Functor with type 'a t = (T.e, 'a) reader = struct | ||
type 'a t = (T.e, 'a) reader | ||
|
||
let fmap : 'a 'b. ('a -> 'b) -> 'a t -> 'b t = | ||
fun f -> function | ||
| Reader r -> Reader (compose f r) | ||
;; | ||
let fmap f (Reader g) = Reader (fun e -> f (g e)) | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
let dumb : 'a. (unit, 'a) reader -> 'a option = function | ||
| Reader _ -> None | ||
;; | ||
let dumb (Reader _) = None |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
let obvious : 'a. (unit, 'a) reader -> 'a option = function | ||
| Reader f -> Some (f ()) | ||
;; | ||
let obvious (Reader g) = Some (g ()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,7 @@ | ||
module Op_Contravariant (T : sig | ||
type r | ||
end) : Contravariant = struct | ||
end) : Contravariant with type 'a t = (T.r, 'a) op = struct | ||
type 'a t = (T.r, 'a) op | ||
|
||
let contramap : ('b -> 'a) -> 'a t -> 'b t = | ||
fun f -> function | ||
| Op g -> Op (compose g f) | ||
;; | ||
let contramap f (Op g) = Op (Fun.compose g f) | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
let pred_to_str = function | ||
| Op f -> Op (fun x -> if f x then "T" else "F") | ||
;; | ||
let pred_to_str (Op f) = Op (fun x -> if f x then "T" else "F") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
compose (contramap f) pred_to_str = compose pred_to_str (contramap f) | ||
contramap f % pred_to_str = pred_to_str % contramap f |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,3 @@ end) | |
|
||
let op_bool_contramap : ('b -> 'a) -> 'a Op_Bool.t -> 'b Op_Bool.t = | ||
Op_Bool.contramap | ||
;; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
('a -> 'a) -> 'a f | ||
('a -> 'a) -> 'a F.t |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
module Chapter2_Bottom : Chapter2_DeclareFunction = struct | ||
let f : bool -> bool = fun _ -> failwith "Not implemented" | ||
ComanderP marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let f : bool -> bool = failwith "Not implemented" | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
let fact n = List.fold (List.range 1 n) ~init:1 ~f:( * ) | ||
let fact n = Seq.(fold_left ( * ) 1 (take n (ints 1))) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
type bool = | ||
| false | ||
| true | ||
type bool = false | true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
module type Monoid = sig | ||
type a | ||
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,7 +1,4 @@ | ||
module type Kleisli = sig | ||
type a | ||
type b | ||
type c | ||
|
||
val ( >=> ) : (a -> b writer) -> (b -> c writer) -> a -> c writer | ||
module type Fish_sig = sig | ||
val ( >=> ) : ('a -> 'b writer) -> | ||
('b -> 'c writer) -> 'a -> 'c writer | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
let pure x = x, "" | ||
let ( >=> ) m1 m2 = | ||
fun x -> | ||
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 @@ | ||
let up_case : string -> string writer = | ||
fun s -> String.uppercase s, "up_case " | ||
;; | ||
let return x = (x, "") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
let to_words : string -> string list writer = | ||
fun s -> String.split s ~on:' ', "to_words " | ||
;; | ||
let up_case (s : string) : string writer = | ||
(String.uppercase_ascii s, "up_case ") | ||
|
||
let to_words (s : string) : string list writer = | ||
(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 | ||
let process : string -> string list writer = | ||
up_case >=> to_words |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
let unit x = () | ||
let unit _ = () |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
compose f g = id | ||
compose g f = id | ||
Fun.compose f g = Fun.id | ||
Fun.compose g f = Fun.id |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,4 @@ | ||
module Chapter5_Product_Example : | ||
Chapter5_Product | ||
with type a = int | ||
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 removed? 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 |
||
and type b = bool | ||
and type c = int = struct | ||
module Chapter5_Product_Example : Chapter5_Product = struct | ||
type a = int | ||
type b = bool | ||
type c = int | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
let p' = compose Chapter5_Product_Example.p m | ||
let q' = compose Chapter5_Product_Example.q m | ||
let p' = Fun.compose Chapter5_Product_Example.p m | ||
let q' = Fun.compose Chapter5_Product_Example.q m |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
let m (x : int) = x, true | ||
let m (x : int) : int * bool = x, true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
let p x = fst (m x) | ||
let q x = snd (m x) | ||
let p x = fst (m x) (* = x *) | ||
let q x = snd (m x) (* = true *) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
fst = compose p m' | ||
snd = compose q m' | ||
let fst = Fun.compose p m' | ||
let snd = Fun.compose q m' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
i' == compose m i | ||
j' == compose m j | ||
let i' = Fun.compose m i | ||
let j' = Fun.compose m j |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
type contact = | ||
| PhoneNum of int | ||
| EmailAddr of string | ||
type contact = PhoneNum of int | EmailAddr of string |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
let helpdesk = PhoneNum 2222222 | ||
let helpdesk : contact = PhoneNum 2222222 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
type ('a, 'b) either = | ||
| Left of 'a | ||
| Right of 'b | ||
(* Available in the [Either] module of the Stdlib *) | ||
type ('a, 'b) either = Left of 'a | Right of 'b |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
let factorizer i j = function | ||
| Left a -> i a | ||
| Right b -> j b | ||
;; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
p = compose fst m | ||
q = compose snd m | ||
let p = Fun.compose fst m | ||
let q = Fun.compose snd m |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
p () = fst (m ()) | ||
q () = snd (m ()) | ||
let p () = fst (m ()) | ||
let q () = snd (m ()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
let stmt = "This statement is", false | ||
(* You cannot do that in OCaml *) | ||
ComanderP marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let stmt = ("This statement is", false) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
let starts_with_symbol (name, symbol, _) = | ||
String.is_prefix name ~prefix:symbol | ||
;; | ||
String.starts_with ~prefix:symbol name |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
let tuple_to_elem (name, symbol, atomic_number) = | ||
{ name; symbol; atomic_number } | ||
;; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
let elem_to_tuple { name; symbol; atomic_number } = | ||
name, symbol, atomic_number | ||
;; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
let starts_with_symbol { name; symbol; _ } = | ||
String.is_prefix name ~prefix:symbol | ||
;; | ||
String.starts_with ~prefix:symbol name |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
(* OCaml only allows special characters in the infix operator. | ||
So, the above function name cannot be applied be infix. *) | ||
So, the above function name cannot be made infix. *) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
type ('a, 'b) either = | ||
| Left of 'a | ||
| Right of 'b | ||
(* Available in the [Either] module of the Stdlib *) | ||
type ('a, 'b) either = Left of 'a | Right of 'b |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
'a void either | ||
('a, void) Either.t |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1 @@ | ||
type color = | ||
| Red | ||
| Green | ||
| Blue | ||
type color = Red | Green | Blue |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
type bool = | ||
| True | ||
| False | ||
type bool = True | False |
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.
I feel like using these specific micro-modules is not really idiomatic for OCaml. Imho it should be more like:
Specifically the name
fmap
is a Haskellism because they need to distinguish it frommap
which is specifically for lists, IIRC. In OCaml we would use the module name for that, sofmap
doesn't really make sense.