I am trying to do this for learning. But I can't get it to work (big surprise since you're reading this :) )
The algo:
I couldn't get the types to work by elegantly lifting sumAggregates
so I tried to do it with pipe, ap
. But I would like to see how we would properly lift sumAggregates
to be used in the reduce.
Please note that my goal isn't to get the correct result in a different way, but to learn why my implementation of this one fails.
type Actionable = {
action?: string
}
type Aggregate = {
allowed: number,
blocked: number
}
const emptyAggregate: Aggregate = {
allowed: 0,
blocked: 0
}
const list: Actionable[] = [ { action: 'block'}, { }, { action: 'block'}, { }, { action: 'allow'}]
const extractAction = (a: Actionable) => a.action
const stringToAggregator = (str: string): Aggregate => {
return {
allowed: str === 'allow' ? 1 : 0,
blocked: str === 'block' ? 1 : 0,
}
}
const sumAggregates = (a: Aggregate) => (b: Aggregate): Aggregate => {
return {
allowed: a.allowed + b.allowed,
blocked: b.blocked + b.blocked,
}
}
const totals: O.Option<Aggregate> = pipe(
list,
A.map(extractAction),
A.map(O.fromNullable),
A.map(O.map(stringToAggregator)),
A.reduce(
O.some(emptyAggregate),
(a: O.Option<Aggregate>, b: O.Option<Aggregate>) => {
return pipe(O.of(sumAggregates), O.ap(a), O.ap(b))
}
)
)
Returns None
instead of some({allowed: 1, blocked: 2})
You end up with None
because one of the elements in the list in the reduce
is a None
, and you pass that None
to O.ap
in the reducer.
Take a look at the definition of ap
for Option
here. The lifted computation does not get called when provided a None
and the result of the ap
becomes None
as a result. So what would you expect the result to be for the following most basic computation?
import * as O from 'fp-ts/Option'
import {identity, pipe} from 'fp-ts/function'
const result: O.Option<number> = pipe(
O.some(identity),
O.ap(O.none),
)
It would be None
right? That is the effect that Option
's apply/applicative instance is known for. So in your reduce
function, once a None
is encountered and passed to ap
, the accumulator ends up in the None
case, and no further applications of sumAggregates
can be performed.