-- Shakespeare, Timon of Athens
Act V, Scene IV, Line 43
Welcome
In Graham Hutton's excellent paper, "A tutorial on the universality and expressiveness of fold", the first function that is looked at is And. Dr. Hutton gives And the following definition:
and :: [Bool] → Bool
and = fold (∧) True
The idea being that we give Fold an And function with a seed value of True. If one of the members of the collection given is False the Anding it with True will yield a value of False and thus the end result will be False. If no member of the collection given is False then the end result will be True.
Let us look at this in 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-and) | |
(defn fold-and | |
"and = fold (∧) True" | |
[& facts] | |
(reduce #(and %1 %2) true 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-and.tests | |
(require | |
[clojure.test :refer [deftest testing are is run-tests]] | |
[fold-and :as sut])) | |
(deftest fold-and-tests | |
(testing "Given all true it must return true" | |
(are [truths] (true? (apply sut/fold-and truths)) | |
[true] | |
[true true] | |
(repeat 100 true))) | |
(testing "Given all false it must return false" | |
(are [falsehoods] (false? (apply sut/fold-and falsehoods)) | |
[false] | |
[false false] | |
(repeat 100 false))) | |
(testing "Given some true and some false it must match every's result" | |
(are [facts] (= (every? identity facts) (apply sut/fold-and facts)) | |
[true] | |
[false true] | |
[true true] | |
[false true] | |
[false false] | |
(repeat 100 true) | |
(repeat 100 false)))) | |
(run-tests) |
To create an Anding function we'll use reduce along with the and macro with a seed of true. Since and is a macro, we'll need to wrap it in a function in order to be able to use it in reduce.
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 Folders | |
{ | |
public class FoldAnd | |
{ | |
public bool And(params bool[] facts) | |
{ | |
return facts.Aggregate(true, (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 System.Linq; | |
using Folders; | |
using Xunit; | |
namespace FoldersTests | |
{ | |
public class FoldAndTests | |
{ | |
[Theory] | |
[InlineData(new[] { true })] | |
[InlineData(new[] { true, true })] | |
[InlineData(new[] { true, true, true })] | |
public void GivenTrueValuesItMustReturnTrue(bool[] truths) | |
{ | |
var sut = new FoldAnd(); | |
var actual = sut.And(truths); | |
Assert.True(actual); | |
} | |
[Theory] | |
[InlineData(new[] { false })] | |
[InlineData(new[] { false, false })] | |
[InlineData(new[] { false, false, false })] | |
public void GivenFalseValuesItMustReturnFalse(bool[] falsehoods) | |
{ | |
var sut = new FoldAnd(); | |
var actual = sut.And(falsehoods); | |
Assert.False(actual); | |
} | |
[Theory] | |
[InlineData(new[] { true })] | |
[InlineData(new[] { false, true })] | |
[InlineData(new[] { true, true })] | |
[InlineData(new[] { false, false })] | |
[InlineData(new[] { false, false, false })] | |
[InlineData(new[] { false, true, false })] | |
[InlineData(new[] { true, true, true })] | |
public void GivenSomeTrueAndSomeFalseValuesItMustReturnFalse(bool[] facts) | |
{ | |
var expected = facts.All(a => a); | |
var sut = new FoldAnd(); | |
var actual = sut.And(facts); | |
Assert.Equal(expected, actual); | |
} | |
} | |
} |
We'll use the LINQ function Aggregate along && and a value of true to create an Anding function.
JavaScript
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
var _ = require("lodash"); | |
exports.foldAnd = function foldAnd(/*facts*/) { | |
var facts = _.toArray(arguments); | |
return _.foldl(facts, function(m, x) {return m && x}, true); | |
}; |
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
var sut = require("../src/foldAnd"), | |
expect = require("expect.js"), | |
_ = require("lodash"); | |
describe("foldAnd", function(){ | |
it("Given all true it must return true", function(){ | |
expect(sut.foldAnd(true)).to.be.ok(); | |
expect(sut.foldAnd(true, true)).to.be.ok(); | |
expect(sut.foldAnd(true, true, true)).to.be.ok(); | |
}), | |
it("Given all false it must return false", function(){ | |
expect(sut.foldAnd(false)).not.to.be.ok(); | |
expect(sut.foldAnd(false, false)).not.to.be.ok(); | |
expect(sut.foldAnd(false, false, false)).not.to.be.ok(); | |
}), | |
it("Given some true and false it must return the same result as every", function(){ | |
expect(sut.foldAnd(true, false)).to.equal(_.every([true, false])); | |
expect(sut.foldAnd(false, true)).to.equal(_.every([false, true])); | |
expect(sut.foldAnd(false, true, false)).to.equal(_.every([false, true, false])); | |
expect(sut.foldAnd(false, false, true)).to.equal(_.every([false, false, true])); | |
}) | |
}); |
We see that by using lodash's foldl function with && and the value true we can create an Anding function.
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.foldAnd = (...facts) => | |
_.foldl(facts, (m, x) => m && x, true); |
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/foldAnd"), | |
expect = require("expect.js"), | |
_ = require("lodash"); | |
describe("foldAnd", () => { | |
it("Given all true it must return true", () => { | |
expect(sut.foldAnd(true)).to.be.ok(); | |
expect(sut.foldAnd(true, true)).to.be.ok(); | |
expect(sut.foldAnd(true, true, true)).to.be.ok(); | |
}), | |
it("Given all false it must return false", () => { | |
expect(sut.foldAnd(false)).not.to.be.ok(); | |
expect(sut.foldAnd(false, false)).not.to.be.ok(); | |
expect(sut.foldAnd(false, false, false)).not.to.be.ok(); | |
}), | |
it("Given some true and false it must return the same result as every", () => { | |
expect(sut.foldAnd(true, false)).to.equal(_.every([true, false])); | |
expect(sut.foldAnd(false, true)).to.equal(_.every([false, true])); | |
expect(sut.foldAnd(false, true, false)).to.equal(_.every([false, true, false])); | |
expect(sut.foldAnd(false, false, true)).to.equal(_.every([false, false, true])); | |
}) | |
}); |
Since we live in the future, we'll use Babel to allow us to use ECMAScript 2015. We see again that by using lodash's foldl with && along with the value true we now have an Anding function.
Fin
There you have it the And function using Fold, showing once again that all you need is Fold.