From c6fa1ac0d42c557b885c519635138b98db916950 Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Tue, 12 Jan 2016 00:29:25 -0800 Subject: [PATCH] Spotchecks --- lib/witchcraft/applicative/function.ex | 14 +++++++- lib/witchcraft/applicative/property.ex | 45 ++++++++++++++------------ 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/lib/witchcraft/applicative/function.ex b/lib/witchcraft/applicative/function.ex index 5f39c19..39af1de 100644 --- a/lib/witchcraft/applicative/function.ex +++ b/lib/witchcraft/applicative/function.ex @@ -5,7 +5,7 @@ defmodule Witchcraft.Applicative.Function do import Kernel, except: [apply: 2] - import Quark, only: [flip: 1] + import Quark, only: [id: 1, flip: 1, constant: 2] import Quark.Curry, only: [curry: 1] import Witchcraft.Applicative, only: [apply: 2] @@ -31,4 +31,16 @@ defmodule Witchcraft.Applicative.Function do @spec lift(any, (... -> any)) :: any def lift([value], fun), do: value ~> curry(fun) def lift([head|tail], fun), do: Enum.reduce(tail, lift([head], fun), &apply/2) + + @doc ~S""" + Sequentially `apply`, and discard the second value of each pair. + """ + @spec seq_first([any]) :: any + def seq_first([a,b]), do: lift([a,b], &constant/2) + + @doc ~S""" + Sequentially `apply`, and discard the first value of each pair. + """ + @spec seq_second([any]) :: any + def seq_second([a,b]), do: lift([a,b], fn x -> constant(x, &id/1) end) end diff --git a/lib/witchcraft/applicative/property.ex b/lib/witchcraft/applicative/property.ex index a4784d4..77f43e0 100644 --- a/lib/witchcraft/applicative/property.ex +++ b/lib/witchcraft/applicative/property.ex @@ -32,17 +32,18 @@ defmodule Witchcraft.Applicative.Property do @spec spotcheck_identity(any) :: boolean def spotcheck_identity(value), do: (value ~>> wrap(value, &id/1)) == value - # @doc ~S""" - # `apply` composes normally. + @doc ~S""" + `apply` composes normally. + + iex> spotcheck_composition([1, 2], [&(&1 * 2)], [&(&1 * 10)]) + true - # iex> spotcheck_composition([1, 2], [&(&1)], [&(&1 * 2)], [&(&1 * 10)]) - # true + """ + @spec spotcheck_composition(any, any, any) :: boolean + def spotcheck_composition(value, fun1, fun2) do + wrap(value, &compose/2) <<~ fun1 <<~ fun2 <<~ value == fun1 <<~ (fun2 <<~ value) + end - # """ - # # @spec - # def spotcheck_composition(x, u, v, w) do - # x ~>> (wrap(u, &compose/2) <<~ u <<~ v <<~ w) == x ~>> u ~>> (v ~>> w) - # end @doc ~S""" `apply`ing a `wrap`ped function to a `wrap`ped value is the same as wrapping the result of the function on that value. @@ -60,21 +61,23 @@ defmodule Witchcraft.Applicative.Property do wrap(specemin, val) ~>> wrap(specemin, curried) == wrap(specemin, curried.(val)) end - # @doc ~S""" - # The order does not matter when `apply`ing to a `wrap`ped value - # and a `wrap`ped function. + @doc ~S""" + The order does not matter when `apply`ing to a `wrap`ped value + and a `wrap`ped function. + + ```elixir - # ```elixir + iex> spotcheck_interchange(1, [&(&1 * 10)]) + true - # iex> spotcheck_interchange(1, [&(&1 * 10)]) - # true + ``` - # ``` - # """ - # @spec spotcheck_interchange(any, any) :: boolean - # def spotcheck_interchange(bare_val, wrapped_fun) do - # wrap(wrapped_fun, bare_val) ~>> wrapped_fun == wrapped_fun ~>> wrap(wrapped_fun, &(bare_val |> &1)) - # end + """ + @spec spotcheck_interchange(any, any) :: boolean + def spotcheck_interchange(bare_val, wrapped_fun) do + wrap(wrapped_fun, bare_val) ~>> wrapped_fun + == wrapped_fun ~>> wrap(wrapped_fun, &(bare_val |> curry(&1).())) + end @doc ~S"""