F# F中的函数模板#
假设我正在解决一个特定的问题,并提出了一个函数F# F中的函数模板#,f#,inline,F#,Inline,假设我正在解决一个特定的问题,并提出了一个函数 let function parameter1 ... = a lot of adding, multiplying & so on with a lot of literals all over the place 现在,如果我的参数是int类型,那么这个函数可以正常工作。但是在某些地方,我需要它上升到11,我需要额外的推力进入int64甚至biginger。那我该怎么办? 我复制并粘贴函数,更改名称,并查找所有
let function parameter1 ... =
a lot of adding, multiplying & so on with a lot of
literals all over the place
现在,如果我的参数是int类型,那么这个函数可以正常工作。但是在某些地方,我需要它上升到11,我需要额外的推力进入int64甚至biginger。那我该怎么办?
我复制并粘贴函数,更改名称,并查找所有让编译器认为函数应该在int上运行的文字外观。这太糟糕了
有没有办法做到这一点:
let greatFunction param1 param2 = (param1+1)/(param2*2)
其中param1和param2可以是整数类型的任意组合
编辑:
在下面kvb的一个很棒的技巧上进行了一些扩展,我得出了以下结论
module NumericLiteralG
let inline FromZero() = LanguagePrimitives.GenericZero
let inline FromOne() = LanguagePrimitives.GenericOne
let inline FromInt32 n =
let rec loop nIn nOut =
if nIn>0 then loop (nIn - 1) (nOut + LanguagePrimitives.GenericOne)
else nOut
loop n LanguagePrimitives.GenericZero
所以用起来就不那么难看了
let inline halfSquare num =
let res = num / 2G
res * res
let solve1 = halfSquare 5I
let solve2 = halfSquare 5.0
let solve3 = halfSquare 5uy
现在的问题是我应该用这个吗?如果没有,为什么不呢?这是我的建议。通常,您有两种选择:
- 静态成员约束
- 全局数字关联(在F#PowerPack中提供)
let inline halfSquare num =
let res = LanguagePrimitives.DivideByInt num 2
res * res
一种方法是将
内联
关键字和来自模块的通用位组合在一起:
虽然不是很理想,而且有点绕过了主要问题,但您可以添加类型注释来迫使编译器:
let greatFunction (param1:int64) (param2:int64) : int64 = (param1+1)/(param2*2)
当然,F#中没有隐式转换,所以您需要将
L
添加到所有数字文本中,但它们至少会显示为编译器错误。我认为泛型算术是.NET语言中常见的问题。
有许多文章解释了不同的方法,很快我将发布另一篇文章来解释我的方法,这与您发布的解决方案类似
现在,如果你问我是否应该使用它,我会说:只要你明白你在做什么,为什么不呢?我在生产中部分使用它,完全没有问题,但因为我关心运行时性能,所以我在编译时使用重载来解决所有问题。
然后为了加快编译速度,我重新定义了基本的数学运算符,使其在同一类型中进行操作,否则类型签名会变得非常复杂,编译可能需要很长时间
有更多的事情要考虑,但是对于你的特定问题,这里有一个示例代码:
open System.Numerics
type FromInt = FromInt with
static member ($) (FromInt, _:sbyte ) = fun (x:int) -> sbyte x
static member ($) (FromInt, _:int16 ) = fun (x:int) -> int16 x
static member ($) (FromInt, _:int32 ) = id
static member ($) (FromInt, _:float ) = fun (x:int) -> float x
static member ($) (FromInt, _:float32 ) = fun (x:int) -> float32 x
static member ($) (FromInt, _:int64 ) = fun (x:int) -> int64 x
static member ($) (FromInt, _:nativeint ) = fun (x:int) -> nativeint x
static member ($) (FromInt, _:byte ) = fun (x:int) -> byte x
static member ($) (FromInt, _:uint16 ) = fun (x:int) -> uint16 x
static member ($) (FromInt, _:char ) = fun (x:int) -> char x
static member ($) (FromInt, _:uint32 ) = fun (x:int) -> uint32 x
static member ($) (FromInt, _:uint64 ) = fun (x:int) -> uint64 x
static member ($) (FromInt, _:unativeint) = fun (x:int) -> unativeint x
static member ($) (FromInt, _:bigint ) = fun (x:int) -> bigint x
static member ($) (FromInt, _:decimal ) = fun (x:int) -> decimal x
static member ($) (FromInt, _:Complex ) = fun (x:int) -> Complex(float x,0.0)
let inline fromInt (a:int) : ^t = (FromInt $ Unchecked.defaultof< ^t>) a
module NumericLiteralG =
let inline FromZero() =LanguagePrimitives.GenericZero
let inline FromOne() = LanguagePrimitives.GenericOne
let inline FromInt32 (i:int) = fromInt i
// This will reduce the number of types inferred, will reduce compile time too.
let inline (+) (a:^t) (b:^t) : ^t = a + b
let inline (-) (a:^t) (b:^t) : ^t = a - b
let inline (*) (a:^t) (b:^t) : ^t = a * b
let inline (/) (a:^t) (b:^t) : ^t = a / b
let inline (~-) (a:^t) : ^t = -a
let inline halfSquare num =
let res = num / 2G
res * res
let solve1 = halfSquare 5I
let solve2 = halfSquare 5.0
let solve3 = halfSquare 5uy
// Define more generic math functions.
opensystem.Numerics
键入FromInt=FromInt,并使用
静态成员($)(FromInt,U2;:sbyte)=乐趣(x:int)->sbyte x
静态成员($)(FromInt,U3;:int16)=乐趣(x:int)->int16x
静态成员($)(FromInt,\uInt32)=id
静态成员($)(FromInt,U3;:float)=fun(x:int)->float x
静态成员($)(FromInt,U3;:float32)=fun(x:int)->float32 x
静态成员($)(FromInt,U3;:int64)=乐趣(x:int)->int64 x
静态成员($)(FromInt,U9:nativeint)=乐趣(x:int)->nativeint x
静态成员($)(FromInt,U3:byte)=乐趣(x:int)->字节x
静态成员($)(FromInt,U3;:uint16)=fun(x:int)->uint16 x
静态成员($)(FromInt,U3;:char)=fun(x:int)->char x
静态成员($)(FromInt,U3;:uint32)=fun(x:int)->uint32 x
静态成员($)(FromInt,U3;:uint64)=fun(x:int)->uint64 x
静态成员($)(FromInt,U3:unativeint)=乐趣(x:int)->unativeint x
静态成员($)(FromInt,U3;:bigint)=乐趣(x:int)->bigint x
静态成员($)(FromInt,U3:decimal)=乐趣(x:int)->十进制x
静态成员($)(FromInt,U3;:复数)=fun(x:int)->Complex(float x,0.0)
让内联fromInt(a:int):^t=(fromInt$未选中。默认值<^t>)a
数字文字模块=
让内联FromZero()=LanguagePrimitives.GenericZero
让内联FromOne()=LanguagePrimitives.GenericOne
让内联FromInt32(i:int)=fromInt i
//这将减少推断类型的数量,也将减少编译时间。
设内联(+)(a:^t)(b:^t):^t=a+b
让内联(-)(a:^t)(b:^t):^t=a-b
让内联(*)(a:^t)(b:^t):^t=a*b
让内联(/)(a:^t)(b:^t):^t=a/b
让内联(~-)(a:^t):^t=-a
让内联半平方数=
设res=num/2G
res*res
设solve1=半正方形5I
设solve2=半正方形5.0
设solve3=半平方5uy
//定义更通用的数学函数。
我认为,一般来说,您需要一个数值类/接口来实现这一点,而afaik在.net中还不存在(还?)。但也许一些特殊的F#东西可以帮你。看一看。你为什么问你是否应该用这个?使用GenericXXX
的内联函数是在F#中实现这一点的最终方法。嗨,Daniel。我是F#的新手,我真的在尝试,这意味着我努力以功能性的方式来做,即使我脑海中尖叫的解决方案都是针对循环、副作用、gotos等等。现在,我非常不知道这是如何工作的引擎盖下,来自数字电子/微控制器的背景。我过去知道代码中每条指令的时间。我过去常常手工优化我的编译器输出。因此,这是一个诚实的问题,针对那些比我更了解这个主题的人。我可以做最愚蠢的事情,但我不知道。从这个背景来看,我认为这与C++模板是一样的。注意,inline
无处不在。我之所以这么问,原因是:这家伙显然是复制了我的努力成果,并在两年前将其发布在这里。我的Google Fu很弱。这是一篇非常有趣的文章。没有真正关注整型->整型的东西,这让我想知道,这就是我所要求的在F#中真的那么不寻常吗?或者,这是一件小事,每个人都知道,而我是唯一一个在互联网上要求它的人?与此同时,在阅读了上述文章后,我想到了这个:让内联genericnn=let rec loop nIn nOut=if nInGenericZero then loop(nIn-GenericOne)(nOut+GenericOne)else nOut loop n GenericZero let inline halfSquare num=let res=num/(genericN 2)res*res问题
open System.Numerics
type FromInt = FromInt with
static member ($) (FromInt, _:sbyte ) = fun (x:int) -> sbyte x
static member ($) (FromInt, _:int16 ) = fun (x:int) -> int16 x
static member ($) (FromInt, _:int32 ) = id
static member ($) (FromInt, _:float ) = fun (x:int) -> float x
static member ($) (FromInt, _:float32 ) = fun (x:int) -> float32 x
static member ($) (FromInt, _:int64 ) = fun (x:int) -> int64 x
static member ($) (FromInt, _:nativeint ) = fun (x:int) -> nativeint x
static member ($) (FromInt, _:byte ) = fun (x:int) -> byte x
static member ($) (FromInt, _:uint16 ) = fun (x:int) -> uint16 x
static member ($) (FromInt, _:char ) = fun (x:int) -> char x
static member ($) (FromInt, _:uint32 ) = fun (x:int) -> uint32 x
static member ($) (FromInt, _:uint64 ) = fun (x:int) -> uint64 x
static member ($) (FromInt, _:unativeint) = fun (x:int) -> unativeint x
static member ($) (FromInt, _:bigint ) = fun (x:int) -> bigint x
static member ($) (FromInt, _:decimal ) = fun (x:int) -> decimal x
static member ($) (FromInt, _:Complex ) = fun (x:int) -> Complex(float x,0.0)
let inline fromInt (a:int) : ^t = (FromInt $ Unchecked.defaultof< ^t>) a
module NumericLiteralG =
let inline FromZero() =LanguagePrimitives.GenericZero
let inline FromOne() = LanguagePrimitives.GenericOne
let inline FromInt32 (i:int) = fromInt i
// This will reduce the number of types inferred, will reduce compile time too.
let inline (+) (a:^t) (b:^t) : ^t = a + b
let inline (-) (a:^t) (b:^t) : ^t = a - b
let inline (*) (a:^t) (b:^t) : ^t = a * b
let inline (/) (a:^t) (b:^t) : ^t = a / b
let inline (~-) (a:^t) : ^t = -a
let inline halfSquare num =
let res = num / 2G
res * res
let solve1 = halfSquare 5I
let solve2 = halfSquare 5.0
let solve3 = halfSquare 5uy
// Define more generic math functions.