如何在F#中实现abs,sign等

Yin*_*Zhu 6 f# inline

我找到:

abs -10
abs -10L
Run Code Online (Sandbox Code Playgroud)

都工作.所以我想知道F#是如何实现这个并在源代码中进行搜索的:

    type AbsDynamicImplTable<'T>() = 
    let AbsDynamic x            = AbsDynamicImplTable<_>.Result x

    [<CompiledName("Abs")>]
    let inline abs (x: ^T) : ^T = 
         AbsDynamic x
         when ^T : ^T = absImpl x
Run Code Online (Sandbox Code Playgroud)

我对这些感到困惑.

正如我所知,在函数中abs,我们必须将输入与0进行比较,并且对于不同的类型有不同的0.

谢谢.

Tom*_*cek 13

为了向ChaosPandion发布的代码添加一些解释,F#函数的问题abs是它们可以使用任何数字类型.有没有办法来表达这只是使用F#/.NET泛型-唯一支持的约束是类型参数实现某个接口或有一个构造函数,但对于数值类型没有限制.

因此,F#还支持静态约束(类型参数^a代替通常'a),并且这些在编译时使用内联进行处理(这也解释了函数必须的原因inline).您可以使用内置函数编写具有静态约束的函数,LanguagePrimitives其中包含许多需要一些约束的有用函数:

> let inline half (num: ^a) : ^a =
     LanguagePrimitives.DivideByInt< (^a) > num 2
  ;;
val inline half : ^a -> ^a 
   when ^a : (static member DivideByInt : ^a * int -> ^a)

> half 42.0;;
val it : float = 21.0

> half 42.0f;;
val it : float32 = 21.0f
Run Code Online (Sandbox Code Playgroud)

需要注意的是约束推断- DivideByInt要求该类型有DivideByInt成员,所以我们的函数需要同样的事情(和它会用自己的类型的工作,如果它有这个成员也是如此,这是非常有用的!).

除此之外,实现abs使用仅在F#库中允许的两个附加技巧 - 它为不同类型(使用when ^a:int = ....)指定不同的代码(在内联时使用)和使用Abs成员的后备情况,因此它将使用任何明确列出的类型或具有Abs成员的类型.另一个技巧是retype"更改类型" 的函数,但不包含任何代码 - 唯一的目的是进行代码类型检查,但这可能非常不安全 - 因此仅在F#库中使用.


Cha*_*ion 8

实际上,Abs表会称之为:

let inline abs_impl (x: ^a) : ^a = 
     (^a: (static member Abs : ^a -> ^a) (x))
     when ^a : int32       = let x : int32     = retype x in if x >= 0 then x else -x
     when ^a : float       = let x : float     = retype x in if x >= 0.0 then x else -x
     when ^a : float32     = let x : float32   = retype x in if x >= 0.0f then x else -x
     when ^a : int64       = let x : int64     = retype x in if x >= 0L then x else -x
     when ^a : nativeint   = let x : nativeint = retype x in if x >= 0n then x else -x
     when ^a : int16       = let x : int16     = retype x in if x >= 0s then x else -x
     when ^a : sbyte       = let x : sbyte     = retype x in if x >= 0y then x else -x
     when ^a : decimal     = System.Math.Abs(retype x : decimal) 
Run Code Online (Sandbox Code Playgroud)