1

The desired final typescript code is:

transform(input)(transformation1)(transformation2)(...
// input is any data, e.g. string or object
// transformationX should be a transforming function

I've wrote the code below so far, and I feel like I am inventing the wheel, i.e. something like this must be already implemented in FP, but I don't know how it is called. Can anyone tell which tool from https://gcanti.github.io/fp-ts/ can be used instead?

type Transformer = (transformation: Transformation) => Transformer
type Transformation = (input: object) => Transformer

const TranformerCreator = (input: object): Transformer
    => (transformation: Transformation): Transformer
        => transformation(input)

const transform: Transformation = (input: object) => {
    return TranformerCreator(input)
}

const transformation1: Transformation = (input: object) => {
    // do sometging with input

    return TranformerCreator(input)
}
Nurbol Alpysbayev
  • 19,522
  • 3
  • 54
  • 89
  • 1
    I think you want compose/pipe, although that's a really weird way to use it. More normal would be something like `const transformString = pipe(trim, toUpperCase, add('foo')); const xformed = transformString(' bar '); // BARfoo` – Jared Smith Aug 31 '18 at 11:14

1 Answers1

3

It's the continuation monad, where function application is used as the bind operation

const cont = x =>
  k => k (x)
  
const add1 = x =>
  cont (x + 1)
  
const double = x =>
  cont (x * 2)
  
const square = x =>
  cont (x * x)
  
cont (2) (add1) (double) (square) (console.log)
// 36
// 2 -> add1 -> 3 -> double -> 6 -> square -> 36

Here's another encoding that may make it easier to see how it works. Instead of using function application to bind, explicit bind and unit functions are used. Note: "bind" here is unrelated to Function.prototype.bind and refers to the monad binary operation

class Cont
{ constructor (run)
  { this.run = run
  }
  
  bind (f)
  { return new Cont (k => this.run (x => f (x) .run (k)))
  }
  
  static unit (x)
  { return new Cont (k => k (x))
  }
}

const add1 = x =>
  Cont.unit (x + 1)
  
const double = x =>
  Cont.unit (x * 2)
  
const square = x =>
  Cont.unit (x * x)
  
Cont.unit (2)
  .bind (add1)
  .bind (double)
  .bind (square)
  .run (console.log) // 36
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • Oh, finally. I asked on SO, on reddit and on github, and only you gave me the answer. Thanks!!! – Nurbol Alpysbayev Sep 01 '18 at 06:03
  • Also, your solution is so elegant, unlike mine over-engineered one... Excellent – Nurbol Alpysbayev Sep 01 '18 at 06:05
  • You're very welcome. You may also be interested in [this post](https://stackoverflow.com/a/46918344/633183) and [this post](https://stackoverflow.com/a/50913378/633183) ^_^ – Mulan Sep 01 '18 at 06:06
  • And probably [this post](https://stackoverflow.com/a/46518885/633183) too – Mulan Sep 01 '18 at 06:15
  • Lastly the grossly overloaded term "callback" is often conflated with the subject of continuations – [this post](https://stackoverflow.com/a/46758784/633183) may help to guide you – Mulan Sep 01 '18 at 06:23