From 6c37aad0fe24b3394c00087b33a1db0acd660c07 Mon Sep 17 00:00:00 2001 From: Daniel Harvey Date: Wed, 7 Apr 2021 09:26:50 +0100 Subject: [PATCH 1/2] WIP reader --- exercises/reader.test.ts | 32 ++++++++++++++++++++++++++++++++ exercises/reader.ts | 18 ++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 exercises/reader.test.ts create mode 100644 exercises/reader.ts diff --git a/exercises/reader.test.ts b/exercises/reader.test.ts new file mode 100644 index 0000000..248d87d --- /dev/null +++ b/exercises/reader.test.ts @@ -0,0 +1,32 @@ +import * as Read from './reader' +import * as R from 'fp-ts/Reader' +import * as M from 'fp-ts/Monoid' + +describe('reader', () => { + it('one', () => { + expect(Read.one([R.of(1), R.of(2), R.of(3)])(true)).toEqual(6) + expect(Read.one([])(true)).toEqual(0) + }) + it('two', () => { + expect( + Read.two([R.of(1), R.of(2), R.of(3)], M.monoidSum)(true) + ).toEqual(6) + expect(Read.two([], M.monoidSum)(true)).toEqual(0) + + const reader2 = Read.two( + [R.of(1), R.of(2), R.of(3), (a: number) => a + 1], + M.monoidProduct + ) + expect(reader2(10)).toEqual(66) + expect(reader2(-1)).toEqual(0) + }) + it('three', () => { + const reader = Read.three( + a => b => `${a} + ${b}`, + (rA: number) => rA * 2, + (rB: number) => rB * 3 + ) + expect(reader(0)).toEqual('0 + 0') + expect(reader(2)).toEqual('4 + 6') + }) +}) diff --git a/exercises/reader.ts b/exercises/reader.ts new file mode 100644 index 0000000..f2cfee1 --- /dev/null +++ b/exercises/reader.ts @@ -0,0 +1,18 @@ +import * as R from 'fp-ts/Reader' +import * as M from 'fp-ts/Monoid' +import { pipe } from 'fp-ts/function' + +export const one = ( + as: R.Reader[] +): R.Reader => pipe(as, M.fold(R.getMonoid(M.monoidSum))) + +export const two = ( + as: R.Reader[], + monoid: M.Monoid +): R.Reader => pipe(as, M.fold(R.getMonoid(monoid))) + +export const three = ( + f: (a: A) => (b: B) => C, + readerA: R.Reader, + readerB: R.Reader +): R.Reader => pipe(readerA, R.map(f), R.ap(readerB)) From 1e963cc285aaa920b719aaf6a228838dd379cd0b Mon Sep 17 00:00:00 2001 From: Daniel Harvey Date: Sat, 10 Apr 2021 10:27:47 +0100 Subject: [PATCH 2/2] Another exercise --- exercises/reader.test.ts | 38 ++++++++++++++++++++++++++++++++++++++ exercises/reader.ts | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/exercises/reader.test.ts b/exercises/reader.test.ts index 248d87d..9d6d58c 100644 --- a/exercises/reader.test.ts +++ b/exercises/reader.test.ts @@ -29,4 +29,42 @@ describe('reader', () => { expect(reader(0)).toEqual('0 + 0') expect(reader(2)).toEqual('4 + 6') }) + it('four', () => { + const translationsEnglish = { + greeting: 'Good morning', + happyBirthday: 'Happy birthday', + genericPleasantry: 'Have a nice day', + } + const reader = Read.four('Mr Horse', new Date('2020-01-01')) + expect( + reader({ + translations: translationsEnglish, + date: new Date('2020-01-01'), + }) + ).toEqual('Good morning, Mr Horse! Happy birthday!') + expect( + reader({ + translations: translationsEnglish, + date: new Date('2021-02-01'), + }) + ).toEqual('Good morning, Mr Horse! Have a nice day.') + + const translationsItalian = { + greeting: 'Buongiorno', + happyBirthday: 'Buon compleanno', + genericPleasantry: 'Buona giornata', + } + expect( + reader({ + translations: translationsItalian, + date: new Date('2020-01-01'), + }) + ).toEqual('Buongiorno, Mr Horse! Buon compleanno!') + expect( + reader({ + translations: translationsItalian, + date: new Date('2021-02-01'), + }) + ).toEqual('Buongiorno, Mr Horse! Buona giornata.') + }) }) diff --git a/exercises/reader.ts b/exercises/reader.ts index f2cfee1..7e46eeb 100644 --- a/exercises/reader.ts +++ b/exercises/reader.ts @@ -1,18 +1,54 @@ import * as R from 'fp-ts/Reader' import * as M from 'fp-ts/Monoid' import { pipe } from 'fp-ts/function' +import * as A from 'fp-ts/Apply' +// given an array of Reader values, return one return value with all the values +// inside summed export const one = ( as: R.Reader[] ): R.Reader => pipe(as, M.fold(R.getMonoid(M.monoidSum))) +// given an array of Reader values, and a Monoid that knows how to combine the +// values, return a single Reader value with all the contents combined export const two = ( as: R.Reader[], monoid: M.Monoid ): R.Reader => pipe(as, M.fold(R.getMonoid(monoid))) +// given a function shaped `A` -> `B` -> `C`, a Reader and a Reader, +// return a Reader export const three = ( f: (a: A) => (b: B) => C, readerA: R.Reader, readerB: R.Reader ): R.Reader => pipe(readerA, R.map(f), R.ap(readerB)) + +type Env = { + translations: { + greeting: string + happyBirthday: string + genericPleasantry: string + } + date: Date +} + +const thingOne = (name: string) => ({ translations }: Env) => + `${translations.greeting}, ${name}!` + +const thingTwo = (birthday: Date) => ({ date, translations }: Env) => + date.getMonth() == birthday.getMonth() && + date.getDate() == birthday.getDate() + ? `${translations.happyBirthday}!` + : `${translations.genericPleasantry}.` + +// given the functions `thingOne` and `thingTwo`, combine them to make a +// function that creates a birthday greeting. +export const four = ( + name: string, + birthday: Date +): R.Reader => + pipe( + A.sequenceT(R.reader)(thingOne(name), thingTwo(birthday)), + R.map(([a, b]) => `${a} ${b}`) + )