3

I have been doing functional programming for quite some time now, but I am new to monoids and other pure abstractions. I am wondering if there is a way to generate a list of values by using concat function defined for a monoid?

For example, with 0 as identity (unit) and + as concat, integers become a monoid. If I want to have a sequence of ordered integers, I could just apply + to the first integer I need and 1 (which would be a step here), then repeat the process for the result and so on. This would generate a list like [1, 2, 3, 4, 5, ...].

Similarly for more complex monoids, if there is Event monoid defined, with special value as identity and concat such that it takes two Events and produces a new one keeping the same interval, I could have a sequence of [ Event(Today, 12:00), Event(Today, 12:10), Event(Today, 12:20) ] (so the interval is 10 minutes).

My question is: is there any standard pattern/abstraction/way of genereting such sequences by applying concat to previous item and a step/interval? I am using fp-ts library and I tried to find something that could do it, but without any luck. I could use unfold to generate an array of values, but this function passes only one value to the callback while I need two values for concat to work

tht
  • 31
  • 2
  • 1
    Why do you think `unfold` only works with integers? – Bergi Jun 03 '21 at 23:38
  • I believe you should just define your `concat` method. https://gcanti.github.io/fp-ts/modules/Monoid.ts.html – captain-yossarian from Ukraine Jun 04 '21 at 06:57
  • @Bergi sorry I got confused myself, I have edited the part about `unfold`. – tht Jun 04 '21 at 15:20
  • "*I need two values for concat to work*" - the second value is the `step` (i.e. `1` in your first example, `10min` in your second) – Bergi Jun 04 '21 at 15:23
  • This makes sense. But I thought that both parameters to `concat` should be of the same type. My Event is a _tagged union_ wrapping Date (to allow me to define `empty` as EmptyEvent, as there is no native empty for a date), interval is a `number`. Or am I overcomplicating here? – tht Jun 04 '21 at 15:32

1 Answers1

0

this function passes only one value to the callback while I need two values for concat to work

Here's the type of unfold from the Array module:

export declare const unfold: <A, B>(b: B, f: (b: B) => O.Option<readonly [A, B]>) => A[]

Although it may seem like B can only be ‘one value’, you can always return a tuple so that you have access to more than one value in f.

fp-ts does not currently support infinite lists, so here’s an example of using a length parameter to limit the size of the result:

import * as A from 'fp-ts/Array'
import {none, some} from 'fp-ts/Option'
import type {Monoid} from 'fp-ts/Monoid'

const concatList = <M>(M: Monoid<M>) => (step: M) => (length: number): M[] =>
  A.unfold<M, [M, number]>([M.empty, 0], ([prev, currentLength]) => {
    if (currentLength === length) return none
    const next = M.concat(prev, step)
    return some([next, [next, currentLength + 1]])
  })

Usage:

import {MonoidSum} from 'fp-ts/number'

concatList(MonoidSum)(1)(5) // [1, 2, 3,  4,  5]
concatList(MonoidSum)(3)(5) // [3, 6, 9, 12, 15]
Lauren Yim
  • 12,700
  • 2
  • 32
  • 59