Javascript 递归函数的流注释

Javascript 递归函数的流注释,javascript,functional-programming,flowtype,Javascript,Functional Programming,Flowtype,我对如何为此类函数编写流类型注释感兴趣: const Box = x => ({ map: f => Box(f(x)), fold: f => f(x), }); 我想类型注释应该使用泛型。 函数使用示例: const getRandomColor = (): string => Box(Math.random()) .map(x => x * 0xFFFFFF) .map(Math.floor) .map(x => x

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

const Box = x => ({
  map: f => Box(f(x)),
  fold: f => f(x),
});
我想类型注释应该使用泛型。
函数使用示例:

const getRandomColor = (): string =>
  Box(Math.random())
    .map(x => x * 0xFFFFFF)
    .map(Math.floor)
    .map(x => x.toString(16))
    .fold(x => `#${x.padStart(0, 6)}`);
p.S.:如果这是不可能的,请写一份解释为什么不可能。

不幸的是,@Isitea的答案不合适,因为他更改了源代码,而这不是重点。

我不确定你想要什么

如果您使用的是“带babel的流类型检查器”,我认为下面的代码就是您想要得到的

更新: 不确定是否可能,注释中有一个链接指向
map
方法的反例

原始答复: 对!!确实有可能:

const Box = <T1>(x:T1): Box<T1> => {
  return {
    map: <T2>(f): Box<T2> => Box(f(x)),
    fold: <T3>(f): T3 => f(x),
  };
};

function takesBoxedString (b: Box<string>):string { return b.fold(s => s + '') }
let boxedNum = Box(3);
let boxedString = Box('foo');
      
takesBoxedString(boxedString); // fine
takesBoxedString(boxedNum);    // compiler complains
const-Box=(x:T1):Box=>{
返回{
map:(f):Box=>Box(f(x)),
折叠:(f):T3=>f(x),
};
};
函数takesBoxedString(b:Box):字符串{返回b.fold(s=>s+'')
设boxedNum=Box(3);
设boxedString=Box('foo');
takesBoxedString(boxedString);//好的
takesBoxedString(boxedNum);//编译器抱怨

当我开始写这篇文章时,我对流泛型不太了解,但现在我对它们有了更好的欣赏。以下是答案。

@Jared的答案只让我们了解了一部分,但要注意它没有强制执行的东西

我们希望如何使用flow的


你的问题是什么?不清楚吗?我对如何编写流类型注释感兴趣?@user633183,是的,我仍在尝试使用泛型来表达它,但我找不到正确的解决方案。也许,这真的不可能。我不认为
Box
有类型(伪类型注释):
Box::a->{map:(a->b)->折叠:(a->b)->b}
。您将如何注释
map
s返回值的类型?这是无限类型递归。@f或者我不这么认为,如果Box是用泛型类型
t
参数化的,那么
f
必须是
t->b
map:(t->Box)
对吗?谢谢@Isitea的尝试,但是
any
不是我想要的。你的解决方案就像根本没有解决方案一样。我想介绍这段代码的强类型,如Ocaml或haskell中的强类型,比如flow。你为什么不知道我想要什么D这很清楚-使用flow进行类型覆盖:)@KonstantinYakushin作为代码,在同一个名称下分配了几个类型。不可能检查静态类型,这更接近事实。我想知道为什么这是不可能的。只要相信在haskell这样的强静态类型语言中,这样的代码是可能的。@KonstantinYakushin我编辑了一个答案。如果您确实想严格控制变量的类型,则需要单独使用变量作为类型。不要在“相同名称”的变量上混合输入。当然可以,但看起来很奇怪<代码>框本身已参数化,并返回一个包含两个以上类型参数的
对象。为什么
T2
/
T3
不是
类型的一部分?为什么不进一步指定
f
。这是真的吗+不管怎样。@ftor怀疑它在所有情况下都是可靠的。在流程中,我认为没有必要(可能?)要将参数类型添加到函数参数的签名中:在声明函数
f
的位置指定参数类型,并暗示
f::T1->T2
用于
map
等,但必须指定返回值,因为它定义了
框的部分结构(iirc流主要使用结构类型)我实际上研究并实现了Javascript中的行多态性,AFAIK是一种结构类型。但这似乎与流的作用没有任何重叠。我想reasonML是更好的选择。这些泛型的执行力度比你想象的要小;在了解这种解决方案的缺陷之前,请不要建议这种解决方案。有关详细信息,请参阅。我想知道在给定语法的情况下,使用类是否会更容易。
const Box = <T1>(x:T1): Box<T1> => {
  return {
    map: <T2>(f): Box<T2> => Box(f(x)),
    fold: <T3>(f): T3 => f(x),
  };
};

function takesBoxedString (b: Box<string>):string { return b.fold(s => s + '') }
let boxedNum = Box(3);
let boxedString = Box('foo');
      
takesBoxedString(boxedString); // fine
takesBoxedString(boxedNum);    // compiler complains
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 b : Box<string> =
  new Box("1")

b.map(numberToString) // wups! flow doesn't mind!
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.
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.