diff --git a/doc/404.html b/doc/404.html index 8137351..cab18c9 100644 --- a/doc/404.html +++ b/doc/404.html @@ -4,7 +4,7 @@ - 404 – Witchcraft v0.0.1 + 404 – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/ADT.Maybe.html b/doc/ADT.Maybe.html index f35a521..92b31e7 100644 --- a/doc/ADT.Maybe.html +++ b/doc/ADT.Maybe.html @@ -4,7 +4,7 @@ - ADT.Maybe – Witchcraft v0.0.1 + ADT.Maybe – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/ADT.MaybePlus.html b/doc/ADT.MaybePlus.html index 832c999..4b5f32f 100644 --- a/doc/ADT.MaybePlus.html +++ b/doc/ADT.MaybePlus.html @@ -4,7 +4,7 @@ - ADT.MaybePlus – Witchcraft v0.0.1 + ADT.MaybePlus – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Applicative.Functions.html b/doc/Witchcraft.Applicative.Functions.html index 2f77deb..4de3c7c 100644 --- a/doc/Witchcraft.Applicative.Functions.html +++ b/doc/Witchcraft.Applicative.Functions.html @@ -4,7 +4,7 @@ - Witchcraft.Applicative.Functions – Witchcraft v0.0.1 + Witchcraft.Applicative.Functions – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Applicative.Properties.html b/doc/Witchcraft.Applicative.Properties.html index cade29a..fa4a000 100644 --- a/doc/Witchcraft.Applicative.Properties.html +++ b/doc/Witchcraft.Applicative.Properties.html @@ -4,7 +4,7 @@ - Witchcraft.Applicative.Properties – Witchcraft v0.0.1 + Witchcraft.Applicative.Properties – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Applicative.html b/doc/Witchcraft.Applicative.html index 5f67c91..cd1990f 100644 --- a/doc/Witchcraft.Applicative.html +++ b/doc/Witchcraft.Applicative.html @@ -4,7 +4,7 @@ - Witchcraft.Applicative – Witchcraft v0.0.1 + Witchcraft.Applicative – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Arrow.Extra.html b/doc/Witchcraft.Arrow.Extra.html index 1e414b5..67a6f79 100644 --- a/doc/Witchcraft.Arrow.Extra.html +++ b/doc/Witchcraft.Arrow.Extra.html @@ -4,7 +4,7 @@ - Witchcraft.Arrow.Extra – Witchcraft v0.0.1 + Witchcraft.Arrow.Extra – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -65,7 +65,7 @@

Witchcraft.Arrow.Extra - + @@ -128,7 +128,7 @@

fanout(f, g) - + @@ -154,7 +154,7 @@

Specs

product(f, g) - + diff --git a/doc/Witchcraft.Arrow.html b/doc/Witchcraft.Arrow.html index 3a70859..1dadd8d 100644 --- a/doc/Witchcraft.Arrow.html +++ b/doc/Witchcraft.Arrow.html @@ -4,7 +4,7 @@ - Witchcraft.Arrow – Witchcraft v0.0.1 + Witchcraft.Arrow – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -67,7 +67,7 @@

protocol - + @@ -235,7 +235,7 @@

arr(b_to_c) - + @@ -261,7 +261,7 @@

Specs

first(arrow) - + @@ -287,7 +287,7 @@

Specs

second(arrow) - + diff --git a/doc/Witchcraft.Category.Extra.html b/doc/Witchcraft.Category.Extra.html index 6d072be..f12a9ac 100644 --- a/doc/Witchcraft.Category.Extra.html +++ b/doc/Witchcraft.Category.Extra.html @@ -4,7 +4,7 @@ - Witchcraft.Category.Extra – Witchcraft v0.0.1 + Witchcraft.Category.Extra – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -65,7 +65,7 @@

Witchcraft.Category.Extra - + @@ -128,7 +128,7 @@

compose_left_to_right(a_to_b, b_to_c) - + @@ -145,7 +145,7 @@

compose_right_to_left(b_to_c, a_to_b) - + diff --git a/doc/Witchcraft.Category.html b/doc/Witchcraft.Category.html index 7b95d80..45cb106 100644 --- a/doc/Witchcraft.Category.html +++ b/doc/Witchcraft.Category.html @@ -4,7 +4,7 @@ - Witchcraft.Category – Witchcraft v0.0.1 + Witchcraft.Category – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -67,7 +67,7 @@

protocol - + @@ -159,7 +159,7 @@

compose(a, b) - + @@ -176,7 +176,7 @@

id(a) - + diff --git a/doc/Witchcraft.Functor.Functions.html b/doc/Witchcraft.Functor.Functions.html index 3c4563b..1e943e3 100644 --- a/doc/Witchcraft.Functor.Functions.html +++ b/doc/Witchcraft.Functor.Functions.html @@ -4,7 +4,7 @@ - Witchcraft.Functor.Functions – Witchcraft v0.0.1 + Witchcraft.Functor.Functions – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Functor.html b/doc/Witchcraft.Functor.html index 99a8fad..4b5fc0c 100644 --- a/doc/Witchcraft.Functor.html +++ b/doc/Witchcraft.Functor.html @@ -4,7 +4,7 @@ - Witchcraft.Functor – Witchcraft v0.0.1 + Witchcraft.Functor – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Monad.Axioms.html b/doc/Witchcraft.Monad.Axioms.html index 607f594..7702409 100644 --- a/doc/Witchcraft.Monad.Axioms.html +++ b/doc/Witchcraft.Monad.Axioms.html @@ -4,7 +4,7 @@ - Witchcraft.Monad.Axioms – Witchcraft v0.0.1 + Witchcraft.Monad.Axioms – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Monad.Functions.html b/doc/Witchcraft.Monad.Functions.html index 1650c71..031d3c7 100644 --- a/doc/Witchcraft.Monad.Functions.html +++ b/doc/Witchcraft.Monad.Functions.html @@ -4,7 +4,7 @@ - Witchcraft.Monad.Functions – Witchcraft v0.0.1 + Witchcraft.Monad.Functions – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Monad.html b/doc/Witchcraft.Monad.html index b7fb5c5..9992e77 100644 --- a/doc/Witchcraft.Monad.html +++ b/doc/Witchcraft.Monad.html @@ -4,7 +4,7 @@ - Witchcraft.Monad – Witchcraft v0.0.1 + Witchcraft.Monad – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.Monoid.Functions.html b/doc/Witchcraft.Monoid.Functions.html index e7281e3..eee8ad5 100644 --- a/doc/Witchcraft.Monoid.Functions.html +++ b/doc/Witchcraft.Monoid.Functions.html @@ -4,7 +4,7 @@ - Witchcraft.Monoid.Functions – Witchcraft v0.0.1 + Witchcraft.Monoid.Functions – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -93,6 +93,9 @@

a <|> b +

Infix variant of Monoid.op

+
+ @@ -122,14 +125,34 @@

a <|> b - + +
+

Specs

+
+ +
any <|> any :: any
+ +
+
+
- +

Infix variant of Monoid.op

+

Example

+
iex> alias Witchcraft.Monoid, as: Monoid
+iex> defimpl Monoid, for: Integer do
+iex>   def identity(_), do: 0
+iex>   def op(a, b), do: a + b
+iex> end
+iex> Monoid.op(1, 4) |> Monoid.op 2 |> Monoid.op 10
+17
+iex> 1 <|> 4 <|> 2 <|> 10
+17
+
diff --git a/doc/Witchcraft.Monoid.Properties.html b/doc/Witchcraft.Monoid.Properties.html index 60a6f96..3f6fb9c 100644 --- a/doc/Witchcraft.Monoid.Properties.html +++ b/doc/Witchcraft.Monoid.Properties.html @@ -4,7 +4,7 @@ - Witchcraft.Monoid.Properties – Witchcraft v0.0.1 + Witchcraft.Monoid.Properties – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -73,7 +73,9 @@

-

Check samples to confirm that your data adheres to monoidal properties

+

Check samples of your monoid to confirm that your data adheres to the +monoidal properties. All members of your datatype should adhere to these rules. +There are placed here as a quick way to spotcheck some of your values.

@@ -87,30 +89,39 @@

Summary

-
+ + +

- Types + Functions

+

Spotcheck all monoid properties

- + +
+
+ - - - -
-

- Functions -

-
+ +

Check that Monoid.op is associative +(ie: brackets don’t matter)

+
+ +
+
+

Check that some member of your monoid combines with the identity to return itself

+
+
@@ -124,22 +135,6 @@

-
-

- - - - Types -

-
-
-
a :: any
- -
- -
-
-
@@ -149,14 +144,14 @@

Functions

-
+
- + - confirm_membership(candidates) + spotcheck(a, b, c) - + @@ -166,13 +161,69 @@

Specs

-
confirm_membership([a]) :: boolean
+
spotcheck(any, any, any) :: boolean
+

Spotcheck all monoid properties

+ +
+
+
+
+ + + + spotcheck_associativity(member1, member2, member3) + + + + + +
+ +
+

Specs

+
+ +
spotcheck_associativity(any, any, any) :: boolean
+ +
+
+ +
+

Check that Monoid.op is associative +(ie: brackets don’t matter)

+ +
+
+
+
+ + + + spotcheck_identity(member) + + + + +
+ +
+

Specs

+
+ +
spotcheck_identity(any) :: boolean
+ +
+
+ +
+

Check that some member of your monoid combines with the identity to return itself

+
diff --git a/doc/Witchcraft.Monoid.html b/doc/Witchcraft.Monoid.html index b00ddf5..7c54d21 100644 --- a/doc/Witchcraft.Monoid.html +++ b/doc/Witchcraft.Monoid.html @@ -4,7 +4,7 @@ - Witchcraft.Monoid – Witchcraft v0.0.1 + Witchcraft.Monoid – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -75,7 +75,7 @@

-

Monoids are a set, plus a binary combining operation (op) that +

Monoids are a set of elements, and a binary combining operation (op) that returns another member of the set.

Properties

Associativity

@@ -97,16 +97,17 @@

Identity element

Examples

Theory

# Pseudocode
-id = 0
+identity = 0
 op = &(&1 + &2) # Integer addition
 op(34, id) == 34
# Pseudocode
-id = 1
+identity = 1
 op = &(&1 * &2) # Integer multiplication
 op(42, id) == 42

Concrete

-
iex> defimpl Monoid, for: Integer do
-iex>   def id(_), do: 0
+
iex> alias Witchcraft.Monoid, as: Monoid
+iex> defimpl Monoid, for: Integer do
+iex>   def identity(_), do: 0
 iex>   def op(a, b), do: a + b
 iex> end
 iex> Monoid.op(1, 4) |> Monoid.op 2 |> Monoid.op 10
@@ -115,7 +116,7 @@ 

Counter-Example

Integer division is not a monoid. Because you cannot divide by zero, the property does not hold for all values in the set.

Notes

-

You can of course use abuse this protocol to define a fake “monoid” that behaves differently. +

You can of course use abuse this protocol to define a fake ‘monoid’ that behaves differently. For the protocol to operate as intended, you need to respect the above properties.

@@ -151,22 +152,12 @@

Get the idenity (‘zero’) element of the monoid by passing in any element of the set

-
-
- - -

Check if the argument is a member of the monoid. -Doubles as a definition of what belongs to the monoid

-
-
@@ -214,39 +205,12 @@

Functions

-
-
- - - - id(a) - - - - - -
- -
-

Specs

-
- -
id(any) :: any
- -
-
- -
-

Get the idenity (‘zero’) element of the monoid by passing in any element of the set

- -
-
-
+ @@ -276,7 +239,7 @@

Specs

op(a, b) - + diff --git a/doc/Witchcraft.Utils.html b/doc/Witchcraft.Utils.html index 0fd4219..ec495f6 100644 --- a/doc/Witchcraft.Utils.html +++ b/doc/Witchcraft.Utils.html @@ -4,7 +4,7 @@ - Witchcraft.Utils – Witchcraft v0.0.1 + Witchcraft.Utils – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/Witchcraft.html b/doc/Witchcraft.html index 09794c0..147143e 100644 --- a/doc/Witchcraft.html +++ b/doc/Witchcraft.html @@ -4,7 +4,7 @@ - Witchcraft – Witchcraft v0.0.1 + Witchcraft – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -65,7 +65,7 @@

Witchcraft - + diff --git a/doc/dist/sidebar_items.js b/doc/dist/sidebar_items.js index 4ac1aed..7636ef3 100644 --- a/doc/dist/sidebar_items.js +++ b/doc/dist/sidebar_items.js @@ -1 +1 @@ -sidebarNodes={"exceptions":[],"extras":[{"id":"extra-api-reference","title":"API Reference","headers":[]},{"id":"extra-readme","title":"README","headers":[{"id":" Installation","anchor":"Installation"}]}],"modules":[{"id":"ADT.Maybe","title":"ADT.Maybe","functions":[{"id":"from_status_tuple/1","anchor":"from_status_tuple/1"},{"id":"just?/1","anchor":"just?/1"},{"id":"nothing?/1","anchor":"nothing?/1"}]},{"id":"ADT.MaybePlus","title":"ADT.MaybePlus","functions":[{"id":"from_status_tuple/1","anchor":"from_status_tuple/1"},{"id":"just?/1","anchor":"just?/1"},{"id":"meta/1","anchor":"meta/1"},{"id":"nothing?/1","anchor":"nothing?/1"}],"types":[{"id":"maybe_plus/2","anchor":"t:maybe_plus/2"}]},{"id":"Witchcraft","title":"Witchcraft"},{"id":"Witchcraft.Applicative.Functions","title":"Witchcraft.Applicative.Functions","functions":[{"id":"<~>/2","anchor":"%3C~%3E/2"},{"id":"lift2/3","anchor":"lift2/3"},{"id":"lift3/4","anchor":"lift3/4"},{"id":"prior/2","anchor":"prior/2"},{"id":"then/2","anchor":"then/2"},{"id":"wrap/1","anchor":"wrap/1"}]},{"id":"Witchcraft.Applicative.Properties","title":"Witchcraft.Applicative.Properties","functions":[{"id":"homomorphism/2","anchor":"homomorphism/2"},{"id":"identity/2","anchor":"identity/2"}]},{"id":"Witchcraft.Arrow.Extra","title":"Witchcraft.Arrow.Extra","functions":[{"id":"fanout/2","anchor":"fanout/2"},{"id":"product/2","anchor":"product/2"}]},{"id":"Witchcraft.Category.Extra","title":"Witchcraft.Category.Extra","functions":[{"id":"compose_left_to_right/2","anchor":"compose_left_to_right/2"},{"id":"compose_right_to_left/2","anchor":"compose_right_to_left/2"}]},{"id":"Witchcraft.Functor.Functions","title":"Witchcraft.Functor.Functions","functions":[{"id":"<~/2","anchor":"%3C~/2"},{"id":"map_replace/2","anchor":"map_replace/2"},{"id":"~>/2","anchor":"~%3E/2"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"fa/0","anchor":"t:fa/0"},{"id":"fb/0","anchor":"t:fb/0"}]},{"id":"Witchcraft.Monad.Axioms","title":"Witchcraft.Monad.Axioms","functions":[{"id":"neutral_return/1","anchor":"neutral_return/1"},{"id":"neutral_return/2","anchor":"neutral_return/2"},{"id":"rewording/3","anchor":"rewording/3"}]},{"id":"Witchcraft.Monad.Functions","title":"Witchcraft.Monad.Functions","functions":[{"id":"bind/2","anchor":"bind/2"},{"id":"return/1","anchor":"return/1"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"ma/0","anchor":"t:ma/0"},{"id":"mb/0","anchor":"t:mb/0"}]},{"id":"Witchcraft.Monoid.Functions","title":"Witchcraft.Monoid.Functions","functions":[{"id":"<|>/2","anchor":"%3C%7C%3E/2"}]},{"id":"Witchcraft.Monoid.Properties","title":"Witchcraft.Monoid.Properties","functions":[{"id":"confirm_membership/1","anchor":"confirm_membership/1"}],"types":[{"id":"a/0","anchor":"t:a/0"}]},{"id":"Witchcraft.Utils","title":"Witchcraft.Utils","functions":[{"id":"compose/1","anchor":"compose/1"},{"id":"const/2","anchor":"const/2"},{"id":"id/1","anchor":"id/1"}]}],"protocols":[{"id":"Witchcraft.Applicative","title":"Witchcraft.Applicative","functions":[{"id":"apply/2","anchor":"apply/2"},{"id":"pure/1","anchor":"pure/1"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"Witchcraft.Arrow","title":"Witchcraft.Arrow","functions":[{"id":"arr/1","anchor":"arr/1"},{"id":"first/1","anchor":"first/1"},{"id":"second/1","anchor":"second/1"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"a_to_b/0","anchor":"t:a_to_b/0"},{"id":"arrow/3","anchor":"t:arrow/3"},{"id":"b/0","anchor":"t:b/0"},{"id":"b_to_c/0","anchor":"t:b_to_c/0"},{"id":"c/0","anchor":"t:c/0"},{"id":"split/2","anchor":"t:split/2"},{"id":"t/0","anchor":"t:t/0"}]},{"id":"Witchcraft.Category","title":"Witchcraft.Category","functions":[{"id":"compose/2","anchor":"compose/2"},{"id":"id/1","anchor":"id/1"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"Witchcraft.Functor","title":"Witchcraft.Functor","functions":[{"id":"lift/2","anchor":"lift/2"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"r/0","anchor":"t:r/0"},{"id":"t/0","anchor":"t:t/0"},{"id":"wa/0","anchor":"t:wa/0"},{"id":"wr/0","anchor":"t:wr/0"}]},{"id":"Witchcraft.Monad","title":"Witchcraft.Monad","functions":[{"id":"join/1","anchor":"join/1"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"t/0","anchor":"t:t/0"}]},{"id":"Witchcraft.Monoid","title":"Witchcraft.Monoid","functions":[{"id":"id/1","anchor":"id/1"},{"id":"member?/1","anchor":"member?/1"},{"id":"op/2","anchor":"op/2"}],"types":[{"id":"t/0","anchor":"t:t/0"}]}]} \ No newline at end of file +sidebarNodes={"exceptions":[],"extras":[{"id":"extra-api-reference","title":"API Reference","headers":[]},{"id":"extra-readme","title":"README","headers":[{"id":" Installation","anchor":"Installation"}]}],"modules":[{"id":"ADT.Maybe","title":"ADT.Maybe","functions":[{"id":"from_status_tuple/1","anchor":"from_status_tuple/1"},{"id":"just?/1","anchor":"just?/1"},{"id":"nothing?/1","anchor":"nothing?/1"}]},{"id":"ADT.MaybePlus","title":"ADT.MaybePlus","functions":[{"id":"from_status_tuple/1","anchor":"from_status_tuple/1"},{"id":"just?/1","anchor":"just?/1"},{"id":"meta/1","anchor":"meta/1"},{"id":"nothing?/1","anchor":"nothing?/1"}],"types":[{"id":"maybe_plus/2","anchor":"t:maybe_plus/2"}]},{"id":"Witchcraft","title":"Witchcraft"},{"id":"Witchcraft.Applicative.Functions","title":"Witchcraft.Applicative.Functions","functions":[{"id":"<~>/2","anchor":"%3C~%3E/2"},{"id":"lift2/3","anchor":"lift2/3"},{"id":"lift3/4","anchor":"lift3/4"},{"id":"prior/2","anchor":"prior/2"},{"id":"then/2","anchor":"then/2"},{"id":"wrap/1","anchor":"wrap/1"}]},{"id":"Witchcraft.Applicative.Properties","title":"Witchcraft.Applicative.Properties","functions":[{"id":"homomorphism/2","anchor":"homomorphism/2"},{"id":"identity/2","anchor":"identity/2"}]},{"id":"Witchcraft.Arrow.Extra","title":"Witchcraft.Arrow.Extra","functions":[{"id":"fanout/2","anchor":"fanout/2"},{"id":"product/2","anchor":"product/2"}]},{"id":"Witchcraft.Category.Extra","title":"Witchcraft.Category.Extra","functions":[{"id":"compose_left_to_right/2","anchor":"compose_left_to_right/2"},{"id":"compose_right_to_left/2","anchor":"compose_right_to_left/2"}]},{"id":"Witchcraft.Functor.Functions","title":"Witchcraft.Functor.Functions","functions":[{"id":"<~/2","anchor":"%3C~/2"},{"id":"map_replace/2","anchor":"map_replace/2"},{"id":"~>/2","anchor":"~%3E/2"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"fa/0","anchor":"t:fa/0"},{"id":"fb/0","anchor":"t:fb/0"}]},{"id":"Witchcraft.Monad.Axioms","title":"Witchcraft.Monad.Axioms","functions":[{"id":"neutral_return/1","anchor":"neutral_return/1"},{"id":"neutral_return/2","anchor":"neutral_return/2"},{"id":"rewording/3","anchor":"rewording/3"}]},{"id":"Witchcraft.Monad.Functions","title":"Witchcraft.Monad.Functions","functions":[{"id":"bind/2","anchor":"bind/2"},{"id":"return/1","anchor":"return/1"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"ma/0","anchor":"t:ma/0"},{"id":"mb/0","anchor":"t:mb/0"}]},{"id":"Witchcraft.Monoid.Functions","title":"Witchcraft.Monoid.Functions","functions":[{"id":"<|>/2","anchor":"%3C%7C%3E/2"}]},{"id":"Witchcraft.Monoid.Properties","title":"Witchcraft.Monoid.Properties","functions":[{"id":"spotcheck/3","anchor":"spotcheck/3"},{"id":"spotcheck_associativity/3","anchor":"spotcheck_associativity/3"},{"id":"spotcheck_identity/1","anchor":"spotcheck_identity/1"}]},{"id":"Witchcraft.Utils","title":"Witchcraft.Utils","functions":[{"id":"compose/1","anchor":"compose/1"},{"id":"const/2","anchor":"const/2"},{"id":"id/1","anchor":"id/1"}]}],"protocols":[{"id":"Witchcraft.Applicative","title":"Witchcraft.Applicative","functions":[{"id":"apply/2","anchor":"apply/2"},{"id":"pure/1","anchor":"pure/1"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"Witchcraft.Arrow","title":"Witchcraft.Arrow","functions":[{"id":"arr/1","anchor":"arr/1"},{"id":"first/1","anchor":"first/1"},{"id":"second/1","anchor":"second/1"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"a_to_b/0","anchor":"t:a_to_b/0"},{"id":"arrow/3","anchor":"t:arrow/3"},{"id":"b/0","anchor":"t:b/0"},{"id":"b_to_c/0","anchor":"t:b_to_c/0"},{"id":"c/0","anchor":"t:c/0"},{"id":"split/2","anchor":"t:split/2"},{"id":"t/0","anchor":"t:t/0"}]},{"id":"Witchcraft.Category","title":"Witchcraft.Category","functions":[{"id":"compose/2","anchor":"compose/2"},{"id":"id/1","anchor":"id/1"}],"types":[{"id":"t/0","anchor":"t:t/0"}]},{"id":"Witchcraft.Functor","title":"Witchcraft.Functor","functions":[{"id":"lift/2","anchor":"lift/2"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"r/0","anchor":"t:r/0"},{"id":"t/0","anchor":"t:t/0"},{"id":"wa/0","anchor":"t:wa/0"},{"id":"wr/0","anchor":"t:wr/0"}]},{"id":"Witchcraft.Monad","title":"Witchcraft.Monad","functions":[{"id":"join/1","anchor":"join/1"}],"types":[{"id":"a/0","anchor":"t:a/0"},{"id":"t/0","anchor":"t:t/0"}]},{"id":"Witchcraft.Monoid","title":"Witchcraft.Monoid","functions":[{"id":"identity/1","anchor":"identity/1"},{"id":"op/2","anchor":"op/2"}],"types":[{"id":"t/0","anchor":"t:t/0"}]}]} \ No newline at end of file diff --git a/doc/extra-api-reference.html b/doc/extra-api-reference.html index e75b24b..a348f64 100644 --- a/doc/extra-api-reference.html +++ b/doc/extra-api-reference.html @@ -4,7 +4,7 @@ - API Reference – Witchcraft v0.0.1 + API Reference – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

@@ -137,7 +137,9 @@

Modules

-

Check samples to confirm that your data adheres to monoidal properties

+

Check samples of your monoid to confirm that your data adheres to the +monoidal properties. All members of your datatype should adhere to these rules. +There are placed here as a quick way to spotcheck some of your values

@@ -192,7 +194,7 @@

Protocols

-

Monoids are a set, plus a binary combining operation (op) that +

Monoids are a set of elements, and a binary combining operation (op) that returns another member of the set

diff --git a/doc/extra-readme.html b/doc/extra-readme.html index db32c31..4fb6bfd 100644 --- a/doc/extra-readme.html +++ b/doc/extra-readme.html @@ -4,7 +4,7 @@ - README – Witchcraft v0.0.1 + README – Witchcraft v0.1.0 @@ -28,7 +28,7 @@

Witchcraft

diff --git a/doc/index.html b/doc/index.html index e4b71f8..96a2f3c 100644 --- a/doc/index.html +++ b/doc/index.html @@ -2,7 +2,7 @@ - Witchcraft v0.0.1 – Documentation + Witchcraft v0.1.0 – Documentation diff --git a/lib/witchcraft.ex b/lib/witchcraft.ex index 189db1e..d1539f5 100644 --- a/lib/witchcraft.ex +++ b/lib/witchcraft.ex @@ -1,2 +1,25 @@ defmodule Witchcraft do + import Witchcraft.Monoid + import Witchcraft.Monoid.Functions + import Witchcraft.Monoid.Properties + + # import Witchcraft.Functor + # import Witchcraft.Functor.Functions + # import Witchcraft.Functor.Properties + + # import Witchcraft.Applicative + # import Witchcraft.Applicative.Functions + # import Witchcraft.Applicative.Properties + + # import Witchcraft.Monad + # import Witchcraft.Monad.Functions + # import Witchcraft.Monad.Properties + + # import Witchcraft.Catgegory + # import Witchcraft.Catgegory.Functions + # import Witchcraft.Catgegory.Properties + + # import Witchcraft.Arrow + # import Witchcraft.Arrow.Functions + # import Witchcraft.Arrow.Properties end diff --git a/lib/witchcraft/monoid.ex b/lib/witchcraft/monoid.ex index 5756f94..5c279ad 100644 --- a/lib/witchcraft/monoid.ex +++ b/lib/witchcraft/monoid.ex @@ -1,6 +1,6 @@ defprotocol Witchcraft.Monoid do @moduledoc ~S""" - Monoids are a set, plus a binary combining operation (`op`) that + Monoids are a set of elements, and a binary combining operation (`op`) that returns another member of the set. # Properties @@ -18,26 +18,29 @@ defprotocol Witchcraft.Monoid do ``` # Pseudocode - id = 0 + identity = 0 op = &(&1 + &2) # Integer addition - op(34, id) == 34 + op(34, identity) == 34 ``` ``` # Pseudocode - id = 1 + identity = 1 op = &(&1 * &2) # Integer multiplication - op(42, id) == 42 + op(42, identity) == 42 ``` ## Concrete ``` + + iex> alias Witchcraft.Monoid, as: Monoid iex> defimpl Monoid, for: Integer do - iex> def id(_), do: 0 + iex> def identity(_), do: 0 iex> def op(a, b), do: a + b iex> end iex> Monoid.op(1, 4) |> Monoid.op 2 |> Monoid.op 10 17 + ``` ## Counter-Example @@ -45,19 +48,12 @@ defprotocol Witchcraft.Monoid do Because you cannot divide by zero, the property does not hold for all values in the set. # Notes - You can of course use abuse this protocol to define a fake 'monoid' that behaves differently. + You can of course abuse this protocol to define a fake 'monoid' that behaves differently. For the protocol to operate as intended, you need to respect the above properties. """ - @doc """ - Check if the argument is a member of the monoid. - Doubles as a definition of what belongs to the monoid. - """ - @spec member?(any) :: boolean - def member?(value) - - @doc "Get the idenity ('zero') element of the monoid by passing in any element of the set" - @spec id(any) :: any + @doc "Get the identity ('zero') element of the monoid by passing in any element of the set" + @spec identity(any) :: any def identity(a) @doc "Combine two members of the monoid, and return another member" diff --git a/lib/witchcraft/monoid/functions.ex b/lib/witchcraft/monoid/functions.ex index fff8df5..c3827cf 100644 --- a/lib/witchcraft/monoid/functions.ex +++ b/lib/witchcraft/monoid/functions.ex @@ -1,5 +1,24 @@ defmodule Witchcraft.Monoid.Functions do alias Witchcraft.Monoid, as: Mon + @doc ~S""" + Infix variant of `Monoid.op` + + # Example + ``` + + iex> alias Witchcraft.Monoid, as: Monoid + iex> defimpl Monoid, for: Integer do + iex> def identity(_), do: 0 + iex> def op(a, b), do: a + b + iex> end + iex> Monoid.op(1, 4) |> Monoid.op 2 |> Monoid.op 10 + 17 + iex> 1 <|> 4 <|> 2 <|> 10 + 17 + + ``` + """ + @spec any <|> any :: any def a <|> b, do: Mon.op(a, b) end diff --git a/lib/witchcraft/monoid/properties.ex b/lib/witchcraft/monoid/properties.ex index 129f6c4..1ff234a 100644 --- a/lib/witchcraft/monoid/properties.ex +++ b/lib/witchcraft/monoid/properties.ex @@ -1,27 +1,35 @@ defmodule Witchcraft.Monoid.Properties do @moduledoc """ - Check samples to confirm that your data adheres to monoidal properties + Check samples of your monoid to confirm that your data adheres to the + monoidal properties. *All members* of your datatype should adhere to these rules. + They are placed here as a quick way to spotcheck some of your values. """ - alias Witchcraft.Monoid, as: Mon + import Witchcraft.Monoid + import Witchcraft.Monoid.Functions - @type a :: any - - @spec confirm_membership([a]) :: boolean - def confirm_membership(candidates) do - Enum.reduce(candidates, true, &(&2 and Mon.member?(&1))) + @doc """ + Check that some member of your monoid combines with the identity to return itself + """ + @spec spotcheck_identity(any) :: boolean + def spotcheck_identity(member) do + (identity(member) <|> member) == member end - # @spec test_id :: boolean - # def spotcheck_id(member) do - # op(identity, member) == member - # end - - # def spotcheck_associativity(member1, member2, member3) do - # op(member1, member2) |> op(member3) == member1 |> op(op(member2, member3)) - # end + @doc ~S""" + Check that `Monoid.op` is [associative](https://en.wikipedia.org/wiki/Associative_property) + (ie: brackets don't matter) + """ + @spec spotcheck_associativity(any, any, any) :: boolean + def spotcheck_associativity(member1, member2, member3) do + (member1 <|> (member2 <|> member3)) == ((member1 <|> member2) <|> member3) + end - # def spotcheck(a, b, c) do - # confirm_membership([a, b, c]) and spotcheck_id(a) and spotcheck_associativity(a, b, c) - # end + @doc """ + Spotcheck all monoid properties + """ + @spec spotcheck(any, any, any) :: boolean + def spotcheck(a, b, c) do + spotcheck_identity(a) and spotcheck_associativity(a, b, c) + end end diff --git a/mix.exs b/mix.exs index 10f347c..5e12c98 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule Witchcraft.Mixfile do [app: :witchcraft, name: "Witchcraft", - version: "0.0.1", + version: "0.1.0", elixir: "~> 1.1", source_url: "https://github.com/robot-overlord/witchcraft", diff --git a/test/monoid_test.exs b/test/monoid_test.exs new file mode 100644 index 0000000..2c9ca55 --- /dev/null +++ b/test/monoid_test.exs @@ -0,0 +1,56 @@ +defmodule MonoidTest do + use ExUnit.Case + + import Witchcraft.Monoid + import Witchcraft.Monoid.Functions + import Witchcraft.Monoid.Properties + + doctest Witchcraft.Monoid + doctest Witchcraft.Monoid.Functions + doctest Witchcraft.Monoid.Properties + + # Happy case: Strings + defimpl Witchcraft.Monoid, for: BitString do + def identity(_), do: "" + def op(a, b), do: a <> b + end + + # Sad case: Malformed floats under division + defimpl Witchcraft.Monoid, for: Float do + def identity(_), do: -9.0 + def op(a, b), do: a / b + end + + + test "identity always returns the same value for that datatype" do + assert identity("a") == identity("b") + end + + test "identity combined with itself is the identity" do + assert identity("") <|> identity("") == identity("") + end + + test "left identity" do + assert identity("welp") <|> "o hai" == "o hai" + end + + test "right identity" do + assert "o hai" <|> identity("welp") == "o hai" + end + + test "spotcheck_identity is true for well formed monoids" do + assert spotcheck_identity("well formed") == true + end + + test "spotcheck_identity is false for malformed monoids" do + assert spotcheck_identity(88.8) == false + end + + test "spotcheck_associativity returns true when monoid is well formed" do + assert spotcheck_associativity("a", "b", "c") == true + end + + test "spotcheck_associativity returns false when monoid is poorly formed" do + assert spotcheck_associativity(-9.1, 42.0, 88.8) == false + end +end