-- Shakespeare, King John
Act IV, Scene II, Line 124
This is the next in the series of post on Dr. Graham Hutton's excellent paper, "A tutorial on the universality and expressiveness of fold", this time around we'll look at Oring. Dr. Hutton has given Oring the following definition:
or :: [Bool] → Bool
or = fold (∨) False
The idea is that we Fold an Or function with a seed value of False. If one of the members of the collection is True we Or it with False giving us True, else if none of the members of the collection are True we will end up with the value of False.
In the simple example below we'll see that if we have a single value of True then the end result will be True.
At the start we have a Seed value of False with collection containing False, True, and False.
Let us now look at this in sweet, sweet code.
In the Clojure code that we use the or macro and a seed value of false in order to create an Oring function using the higher order function of reduce. Since reduce is expecting a function and not a macro we need to create a lambda function to wrap the or macro.
We see in the C# code that we can use the LINQ aggregate method on the collection we are folding. We give the aggregate a seed value of false and in the lambda we simply takes the memorize and the current member and or them.
Using lodash's foldl function along with Babel.js we are able to create an Oring function by folding over the collection and passing it to a lambda function which ors the current member of the collection with the memorize value. We give a seed value of false thus causing the initial value of the memorize to be false.
There you have it an Oring function using nothing but Fold. Thus "proving" that all you need is Fold.
Act IV, Scene II, Line 124
Welcome Back
This is the next in the series of post on Dr. Graham Hutton's excellent paper, "A tutorial on the universality and expressiveness of fold", this time around we'll look at Oring. Dr. Hutton has given Oring the following definition:
or :: [Bool] → Bool
or = fold (∨) False
The idea is that we Fold an Or function with a seed value of False. If one of the members of the collection is True we Or it with False giving us True, else if none of the members of the collection are True we will end up with the value of False.
In the simple example below we'll see that if we have a single value of True then the end result will be True.
At the start we have a Seed value of False with collection containing False, True, and False.
First time the Memorize has False and X has False.
Second time the Memorize has False and X has True.
Third time the Memorize has True and X has False giving use the finally value of True.
Let us now look at this in sweet, sweet code.
Clojure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns fold-or) | |
(defn fold-or | |
"or = fold (∨) False" | |
[& facts] | |
(reduce #(or %1 %2) false facts)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns fold-or.tests | |
(require | |
[clojure.test :refer [deftest testing are run-tests]] | |
[fold-or :as sut])) | |
(deftest fold-or-tests | |
(testing "Given all true it must return true" | |
(are [truths] (true? (apply sut/fold-or truths)) | |
[true] | |
[true true] | |
(repeat 100 true))) | |
(testing "Given all false it must return false" | |
(are [falsehoods] (false? (apply sut/fold-or falsehoods)) | |
[false] | |
[false false] | |
(repeat 100 false))) | |
(testing "Given some true and false it must return true" | |
(are [facts] (true? (apply sut/fold-or facts)) | |
[false true] | |
[true false] | |
[false true false] | |
[true false false]))) | |
(run-tests) |
In the Clojure code that we use the or macro and a seed value of false in order to create an Oring function using the higher order function of reduce. Since reduce is expecting a function and not a macro we need to create a lambda function to wrap the or macro.
C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
namespace Folder | |
{ | |
public static class Folder | |
{ | |
public static bool Or(params bool[] facts) | |
{ | |
return facts.Aggregate(false, (m, x) => m || x); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Xunit; | |
using static Folder.Folder; | |
namespace FolderTests | |
{ | |
public class FolderTests | |
{ | |
[Theory] | |
[InlineData(new[] { true })] | |
[InlineData(new[] { true, true })] | |
[InlineData(new[] { true, true, true })] | |
public void GivenOnlyTrueItMustReturnTrue(bool[] truths) | |
{ | |
Assert.True(Or(truths)); | |
} | |
[Theory] | |
[InlineData(new[] { false })] | |
[InlineData(new[] { false, false })] | |
[InlineData(new[] { false, false, false })] | |
public void GivenOnlyFalseItMustReturnFalse(bool[] falsehoods) | |
{ | |
Assert.False(Or(falsehoods)); | |
} | |
[Theory] | |
[InlineData(new[] { true, false })] | |
[InlineData(new[] { false, true })] | |
[InlineData(new[] { false, true, false })] | |
[InlineData(new[] { false, false, true })] | |
public void GivenSomeTrueAndFalseItMustReturnTrue(bool[] facts) | |
{ | |
Assert.True(Or(facts)); | |
} | |
} | |
} |
We see in the C# code that we can use the LINQ aggregate method on the collection we are folding. We give the aggregate a seed value of false and in the lambda we simply takes the memorize and the current member and or them.
JavaScript (ECMAScript 2015)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let _ = require("lodash"); | |
exports.foldOr = (...facts) => | |
_.foldl(facts, (m, x) => m || x, false); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let sut = require("../src/foldOr"), | |
expect = require("expect.js"); | |
describe("foldOr", () => { | |
it("Given all true it must return true", () => { | |
expect(sut.foldOr(true)).to.be.ok(); | |
expect(sut.foldOr(true, true)).to.be.ok(); | |
expect(sut.foldOr(true, true, true)).to.be.ok(); | |
}), | |
it("Given all false it must return false", () => { | |
expect(sut.foldOr(false)).not.to.be.ok(); | |
expect(sut.foldOr(false, false)).not.to.be.ok(); | |
expect(sut.foldOr(false, false, false)).not.to.be.ok(); | |
}), | |
it("Given some true and false it must return true", () => { | |
expect(sut.foldOr(true, false)).to.be.ok(); | |
expect(sut.foldOr(false, true)).to.be.ok(); | |
expect(sut.foldOr(false, true, false)).to.be.ok(); | |
expect(sut.foldOr(false, false, true)).to.be.ok(); | |
}); | |
}); |
Using lodash's foldl function along with Babel.js we are able to create an Oring function by folding over the collection and passing it to a lambda function which ors the current member of the collection with the memorize value. We give a seed value of false thus causing the initial value of the memorize to be false.
Until Next Time
There you have it an Oring function using nothing but Fold. Thus "proving" that all you need is Fold.