管道和monad如何在JavaScript中一起工作

管道和monad如何在JavaScript中一起工作

本文介绍了管道和monad如何在JavaScript中一起工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过类似的问题和答案,但没有找到直接解决我问题的答案。我正在努力理解如何使用也许或者 Monads



我写了一个像这样的管道函数:

  const _pipe =(f,g)=> async(... args)=>等待g(等待f(... args))

module.exports = {arguments。
pipeAsync:async(... fns)=> {
return await fns.reduce(_pipe)
},
...



$ p
$ b pre $ const $ token constutes = managejwt.maketoken)(x,y)


解决方案

钩子,线和沉子

我不能强调它是多么重要,你不会在所有感觉像你一样的新术语上受到阻碍必须学习 - 函数式编程是关于函数 - 也许您需要了解的唯一功能是它允许您使用参数来抽象部分程序;或者多个参数,如果需要的话(不是这样)并且由你的语言支持(通常是)

为什么我要告诉你这个?那么JavaScript已经有了一个非常好的API来使用内置的 Promise.prototype.then

  //不要重新发明轮子
myPromise.then (f) .then (g) .then (h) ...

But you want to write functional programs, right? This is no problem for the functional programmer. Isolate the behavior you want to abstract (hide), and simply wrap it in a parameterized function – now that you have a function, resume writing your program in a functional style ...

After you do this for a while, you start to notice patterns of abstraction – these patterns will serve as the use cases for all the other things (functors, applicatives, monads, etc) you learn about later – but save those for later – for now, functions ...

Below, we demonstrate left-to-right composition of asynchronous functions via comp. For the purposes of this program, delay is included as a Promises creator, and sq and add1 are sample async functions.

const delay = (ms, x) =>
  new Promise (r => setTimeout (r, ms, x))

const sq = async x =>
  delay (1000, x * x)

const add1 = async x =>
  delay (1000, x + 1)

// just make a function
const comp = (f,g) =>
  // abstract away the sickness
  x => f (x) .then (g)

// resume functional programming
comp (sq, add1) (10)

  // this effect added for demo purposes
  .then (console.log, console.error)

  // 2 seconds later...
  // 101

invent your own convenience

You can make a variadic compose that accepts any number of functions – also notice how this allows you to mix sync and async functions in the same composition – a benefit of plugging right into .then, which automatically promotes non-Promise return values to a Promise

const delay = (ms, x) =>
  new Promise (r => setTimeout (r, ms, x))

const sq = async x =>
  delay (1000, x * x)

const add1 = async x =>
  delay (1000, x + 1)

// make all sorts of functions
const effect = f => x =>
  (f (x), x)

// invent your own convenience
const log =
  effect (console.log)

const comp = (f,g) =>
  x => f (x) .then (g)

const compose = (...fs) =>
  fs.reduce (comp, x => Promise.resolve (x))

// your ritual is complete
compose (log, add1, log, sq, log, add1, log, sq) (10)

  // effect added for demo
  .then (console.log, console.error)

  // 10
  // 1 second later ...
  // 11
  // 1 second later ...
  // 121
  // 1 second later ...
  // 122
  // 1 second later ...
  // 14884

work smarter, not harder

comp and compose are easy-to-digest functions that took almost no effort to write. Because we used built-in .then, all the error-handling stuff gets hooked up for us automatically. You don't have to worry about manually await'ing or try/catch or .catch'ing – yet another benefit of writing our functions this way

no shame in abstraction

Now, that's not to say that every time you write an abstraction it's for the purposes of hiding something bad, but it can be very useful for a variety of tasks – take for example "hiding" the imperative-style while.

const append = (xs, x) =>
  xs.concat ([x])

const fibseq = n => {
  let seq = []
  let a = 0
  let b = 1
  while (n >= 0) {
    n = n - 1
    seq = append (seq, a)
    a = a + b
    b = a - b
  }
  return seq
}

console.log (fibseq (500))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...  ]

But you want to write functional programs, right? This is no problem for the functional programmer. We can make our own looping mechanism but this time it will use functions and expressions instead of statements and side effects – all without sacrificing speed, readability, or stack safety.

Here, loop continuously applies a function using our recur value container. When the function returns a non-recur value, the computation is complete, and the final value is returned.

const recur = (...values) =>
  ({ type: recur, values })

// break the rules sometimes; reinvent a better wheel
const loop = f =>
  {
    let acc = f ()
    while (acc && acc.type === recur)
      acc = f (...acc.values)
    return acc
  }

const fibseq = x =>
  loop ((n = x, seq = [], a = 0, b = 1) =>
    n === 0
      ? seq.concat ([a])
      : recur (n - 1, seq.concat ([a]), a + b, a))

console.time ('loop/recur')
console.log (fibseq (500))
console.timeEnd ('loop/recur')

// [ 0,
//   1,
//   1,
//   2,
//   3,
//   5,
//   8,
//   13,
//   21,
//   34,
//   ... 490 more items ]
// loop/recur: 5ms

nothing is sacred

And remember, you can do whatever you want. There's nothing magical about then – someone, somewhere decided to make it. You could be somebody in some place and just make your own then – here then is a sort of forward-composition function – just like Promise.prototype.then, it automatically applies then to non-then return values; we add this not because it's a particularly good idea, but to show that we can make that kind of behavior if we wanted to

When you understand then, you will have understood the mother of all monads – remember to focus on the mechanics – not the terms

const then = x =>
  x && x.type === then
    ? x
    : Object.assign (f => then (f (x)), { type: then })

const sq = x =>
  then (x * x)

const add1 = x =>
  x + 1

const effect = f => x =>
  (f (x), x)

const log =
  effect (console.log)

then (10) (log) (sq) (log) (add1) (add1) (add1) (log)
// 10
// 100
// 101

sq (2) (sq) (sq) (sq) (log)
// 65536

what language is that?

It doesn't even look like JavaScript anymore – who cares? It's your program and you decide what you want it to look like. A good language won't stand in your way and force you to write your program in any particular style; functional or otherwise

It's actually JavaScript, just uninhibited by misconceptions of what its capable of expressing

then (10) (log) (sq) (log) (add1) (add1) (add1) (log)
// 10
// 100
// 103
// => { Then: 103 }

sq (5) (log) (add1) (log)
// 25
// 26
// => { Then: 26 }

ship it

We just used the names comp and compose in our local snippets, but when you package your program, you should pick names that make sense given your specific context – see Bergi's comment for a recommendation

这篇关于管道和monad如何在JavaScript中一起工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-11 17:00