递归函数的流注释

Slo*_*wyn 4 javascript functional-programming flowtype

我对如何为此类功能编写流类型注释感兴趣:

const Box = x => ({
  map: f => Box(f(x)),
  fold: f => f(x),
});
Run Code Online (Sandbox Code Playgroud)

我猜类型注释应该使用泛型。
函数用法示例:

const getRandomColor = (): string =>
  Box(Math.random())
    .map(x => x * 0xFFFFFF)
    .map(Math.floor)
    .map(x => x.toString(16))
    .fold(x => `#${x.padStart(0, 6)}`);
Run Code Online (Sandbox Code Playgroud)

PS:如果不可能,请写一个解释为什么不可能
不幸的是,@ Isitea的答案不合适,因为他更改了源代码,这不是重点。

Tha*_*you 5

@Jared的答案只会使我们陷入困境,但要注意它没有强制执行的事情。

我们如何使用Flow的泛型编写它

const Box = <A>(x:A): Box<A> => {
  return {
    map: <B>(f: A => B): Box<B> => Box(f(x)),
    fold: <B>(f: A => B): B => f(x),
  }
}
Run Code Online (Sandbox Code Playgroud)

给定一个简单的函数和box的值,我们应该能够验证泛型类型约束是否得到实施

const numberToString = (x: number) : string =>
  String (x)

const b : Box<string> =
  new Box("1")

b.map(numberToString) // wups! flow doesn't mind!
Run Code Online (Sandbox Code Playgroud)

截至目前,这已损坏并且无法正常运行。@mrkev向我们展示了使用类的解决方法

class Box<A> {
  x: A
  constructor (x: A) { this.x = x }
  map<B>(f: A => B): Box<B> { return new Box(f(this.x)) }
  fold<B>(f: A => B): B { return f(this.x) }
}

const numberToString = (x: number) : string =>
  String (x)

const stringToNumber = (x: string): number =>
  Number (x)

const b : Box<string> =
  new Box("1")

// flow accepts this valid program
b.map(stringToNumber)

// flow rejects this invalid program
b.map(numberToString)
//    ^ Cannot call `b.map` with `numberToString` bound to `f` because number [1] is incompatible with string [2] in the first argument.
Run Code Online (Sandbox Code Playgroud)

@thehogfather与预定义共享另一个选择type。这是更接近原始的形式,但需要打字的排放量-什么2X 应该在流量提供了一个更称职的类型系统是必要的。无论如何,它是可行的,所以我们不允许抱怨。

type Box<A> = {
  map: <B>(f: A => B) => Box<B>,
  fold: <B>(f: A => B)=> B
}

const box = <A>(x:A): Box<A> => {
  return {
    map: <B>(f: A => B): Box<B> => box(f(x)),
    fold: <B>(f: A => B): B => f(x),
  }
}

const numberToString = (x: number) : string =>
  String (x)

const stringToNumber = (x: string): number =>
  Number (x)

const b : Box<string> =
  box("1")

// flow accepts this valid program
b.map(stringToNumber)

// flow rejects this invalid program
b.map(numberToString)
//    ^ Cannot call `b.map` with `numberToString` bound to `f` because number [1] is incompatible with string [2] in the first argument.
Run Code Online (Sandbox Code Playgroud)