Skip to content

Instantly share code, notes, and snippets.

@abiodun0
Created October 24, 2017 07:33
Show Gist options
  • Save abiodun0/f95fcecca8acf2d68f83ac9ebcf4fffd to your computer and use it in GitHub Desktop.
Save abiodun0/f95fcecca8acf2d68f83ac9ebcf4fffd to your computer and use it in GitHub Desktop.
This is a simple monoid structure for basic operations of average, addition, product and max
// Definining a simple monoid structure for addtions, multiply and Max utility
var number = [1, 2, 3];
const Sum = (x) => ({
append: (y) => Sum(x + y.val),
val: x
})
Sum.Identity = Sum(0);
const Multiply = (x) => ({
append: (y) => Multiply(x * y.val),
val: x
});
Multiply.Identity = Multiply(1)
const Max = (x) => ({
append: y => Max(x > y.val ? x : y.val),
val: x
});
Max.Identity = Max(-Infinity);
// This was a bit tricky. first you would have to get the sum and the lenght
// each addiont you are making in are just one more length to the length
// except for the initial which is 0, 0
const Average = (sum, length= 1) => ({
append: y => Average(sum + y.sum, length + y.length),
length: length,
sum: sum,
val: length && sum / length
})
Average.Identity = Average(0, 0)
// We only have one function!!!.. how cool is this!!!
const fold = (M, xs) => xs.map(M).reduce((acc, val) => acc.append(val), M.Identity);
// fold(Sum, number).val;
fold(Average, number).val;
@kiggundu
Copy link

So... send an element to an object containing a curried function and its state then use the individual curried functions successively as the reducer such that the final reducer contains the final state after the reduction which can be simply read off. Cui bono?

@abiodun0
Copy link
Author

abiodun0 commented Oct 17, 2018

Yep basically. the map is creating a Monoid instance which applies to append to every reduce function.
The good part of it is. we can easily have for Max Agerage multiply by changing the 38 as follows

fold(Average, number).val;
fold(Max, number).val;
fold(Multiply, number).val;
fold(Sum, number).val;

A use case, combing react elements

const View = computation => ({
  fold: computation,
  
  map: f =>
   View(props => f(computation(props)))

  contramap: g =>
   View(props => computation(g(props))),

  // Borrowed from Brian Lonsdord's talk Oh Composable World
  // See: https://youtu.be/SfWR3dKnFIo?t=21m51s
  append: other =>
    View(props => (
      <div>
        {computation(props)}
        {other.fold(props)}
      </div>
    ))
})
View.of = x => View(() => x)

Now we can append like a boss

const header = View.of(<h1>Awesome App</h1>)
const greeting = View(({ name }) => <p>Hello {name}!</p>)
const footer = View.of(<p>© Bob McBob 2017</p>)

const main = header.map(x => <header style={{ color: 'red' }}>{x}</header>)
  .append(greeting.contramap(() => ({ name: 'Alice' })))
  .append(footer.map(x => <footer style={{ color: 'blue' }}>{x}</footer>))

const centered = main.map(x => <div style={{ textAlign: 'center' }}>{x}</div>)

ReactDOM.render(
  centered.fold(),
  document.querySelector('#root')
)

Not that this also contains contramap and functors, but the main focus is a monoid in this case
@kiggundu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment