Почему функция F# возвращает подпись "val FunctionName: int -> int"?
Я следовал за некоторыми примерами на F# Wikibook о функциях высокого порядка.
Второй фрагмент кода под заголовком, функция композиции имеет следующий фрагмент кода.
#light
open System
let compose f g x = f (g x)
let xSquared x = x*x
let negXPlusFive x = -x/2.0 + 5.0
let fog = compose xSquared negXPlusFive
// ... Console.WriteLine statements....
У меня возникли проблемы с пониманием
let xSquared x = x*x
Когда я запускаю его с помощью интерактивной оболочки F# (fsi.exe), я получаю следующую подпись.
> let xSquared x = x*x;;
val xSquared : int -> int
Но когда я запускаю весь фрагмент кода, xSquared
возвращает следующее.
val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
val xSquared : float -> float
val negXPlusFive : float -> float
val fog : (float -> float)
Почему xSquared
принимает float
и возвращается float
?
2 ответа
Имея больше информации, F# может определить, что xSquared вызывается с аргументами с плавающей точкой. Если вы измените negXPlusFive на что-то вроде "let negXPlusFive x = -x + 5", вы обнаружите, что оно, fog и xSquared будет "int -> int".
Чтобы раскрыть, что сказал Себастьян и что пометил jleedev, нужно выполнить следующую функцию:
let xSquared x = x*x
Может работать только с типом, у которого есть оператор *. По умолчанию int побеждает в этих ситуациях. Он не может быть действительно общим, потому что.NET не имеет способа представления ограничения "любой тип, имеющий *".
Тем не менее, F# поддерживает встраивание, что позволяет функциям быть более универсальными, потому что они встраиваются в каждый сайт вызова. Это позволяет вам иметь такую функцию, как xSquared, которая работает с числами с плавающей запятой, целыми числами и т. Д. - любой тип с оператором *.
> let inline xSquared x = x*x;;
val inline xSquared :
^a -> ^b when ^a : (static member ( * ) : ^a * ^a -> ^b)
Теперь обратите внимание на тип функции ^a -> ^b. Это похоже на 'a -> 'b, за исключением того, что переменные типа должны быть разрешены статически. Поскольку F# не имеет классов типов, это то, как обрабатываются операторы.
На самом деле вы можете определить свой собственный тип с его собственным * членом, чтобы делать все, что вы пожелаете, и он будет работать с xSquared:
type Foo(x) =
member this.Y = x - 1
static member (*) (x:Foo, y:Foo) = string <| x.Y * y.Y + 1
let a = Foo(10);;
type Foo =
class
new : x:int -> Foo
member Y : int
static member ( * ) : x:Foo * y:Foo -> string
end
val a : Foo
> xSquared a;;
val it : string = "82"
Просто откройте prim-types.fs в вашем F# дистрибутиве и покопайтесь. Вокруг строки 2200 находятся определения для >>> и других, которые демонстрируют встраивание и другие изящные вещи.