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.