diff --git a/src/exo0/exo0.test.ts b/src/exo0/exo0.test.ts new file mode 100644 index 0000000..fafec90 --- /dev/null +++ b/src/exo0/exo0.test.ts @@ -0,0 +1,48 @@ +import { isOddF, isOddP, next, next3 } from './exo0'; + +describe('exo0', () => { + describe('isOddP', () => { + it('should return true if the provided number is odd', () => { + const oddValue = 1; + + expect(isOddP(oddValue)).toBe(true); + }); + + it('should return false if the provided number is even', () => { + const oddValue = 2; + + expect(isOddP(oddValue)).toBe(false); + }); + }); + + describe('isOddF', () => { + it('should return true if the provided number is odd', () => { + const oddValue = 1; + + expect(isOddF(oddValue)).toBe(true); + }); + + it('should return false if the provided number is even', () => { + const oddValue = 2; + + expect(isOddF(oddValue)).toBe(false); + }); + }); + + describe('next', () => { + it('should return the correct next element in the Collatz sequence', () => { + expect(next(4)).toBe(2); + expect(next(2)).toBe(1); + expect(next(1)).toBe(4); + }); + }); + + describe('next3', () => { + it('should return the correct element in the Collatz sequence 3 steps ahead', () => { + expect(next3(12)).toBe(10); + expect(next3(10)).toBe(8); + expect(next3(8)).toBe(1); + expect(next3(1)).toBe(1); + }); + }); +}); diff --git a/src/exo0/exo0.ts b/src/exo0/exo0.ts new file mode 100644 index 0000000..6c7fb58 --- /dev/null +++ b/src/exo0/exo0.ts @@ -0,0 +1,71 @@ +// `fp-ts` training introduction +// Composing computations with `pipe` and `flow` + +// Functional programming is all about composing small functions together like +// lego bricks to build more and more complex computations. +// +// Strictly speaking, composing two functions `f` and `g` means applying the +// result of the first one to the second one. By applying this composition +// over and over you can chain multiple functions together. +// +// The `fp-ts` library provides to helpers to do that: +// - `pipe` which first needs to be fed a value to start the pipe and then +// any number of functions to be applied sequentially. +// - `flow` which is the same thing but were we do not have to provide the +// first value. It will then return a function which will expect that value +// to be provided +// +// ```ts +// flow(f, g, h) === x => pipe(x, f, g, h) +// pipe(x, f, g, h) === flow(f, g, h)(x) +// ``` +// +// NOTES: +// - `flow(f) === f` +// - `pipe(x, f) === f(x)` + +import { unimplemented } from '../utils'; + +export const isEven = (value: number) => value % 2 === 0; + +export const not = (value: boolean) => !value; + +/////////////////////////////////////////////////////////////////////////////// +// PIPE & FLOW // +/////////////////////////////////////////////////////////////////////////////// + +// For this exercise each function needs to be implemented using both forms: +// - a `pipe` implementation (P suffix) +// - a `flow` implementation (F suffix) + +// Using only the two helpers `isEven` and `not` at the top of this file (and +// `pipe` or `flow`), write the function `isOdd` that checks if a number is +// odd. + +export const isOddP: (value: number) => boolean = unimplemented; + +export const isOddF: (value: number) => boolean = unimplemented; + +// The Collatz conjecture: https://en.wikipedia.org/wiki/Collatz_conjecture +// +// We will write a function that for any given number, computes the next +// one according to the following rules: +// - if n is even => divide it by two +// - if n is odd => triple it and add one +// +// Below is the functional equivalent of the control flow statement if-else. + +export const ifThenElse = (onTrue: () => A, onFalse: () => A) => ( + condition: boolean, +) => (condition ? onTrue() : onFalse()); + +// Using `pipe` the function that computes the next step in the Collatz +// sequence. + +export const next: (value: number) => number = unimplemented; + +// Using only `flow` and `next`, write the function that for any given number +// a_n from the Collatz sequence, returns the number a_n+3 (ie. the number +// three steps ahead in the sequence). + +export const next3: (value: number) => number = unimplemented; diff --git a/src/exo0/index.ts b/src/exo0/index.ts new file mode 100644 index 0000000..a862d82 --- /dev/null +++ b/src/exo0/index.ts @@ -0,0 +1 @@ +export * from './exo0';