Вопрос

Я пытаюсь выяснить, как определить функцию, которая работает с несколькими типами параметров (напримерint и int64).Насколько я понимаю, перегрузка функций невозможна в F # (конечно, компилятор жалуется).Возьмем, к примеру, следующую функцию.

let sqrt_int = function
    | n:int   -> int (sqrt (float n))
    | n:int64 -> int64 (sqrt (float n))

Компилятор, конечно, жалуется на недопустимый синтаксис (ограничения типа при сопоставлении с образцом, похоже, не поддерживаются), хотя я думаю, что это иллюстрирует то, чего я хотел бы достичь:функция, которая работает с несколькими типами параметров и возвращает значение соответствующего типа.У меня есть ощущение, что это возможно в F #, используя некоторую комбинацию общих типов / вывода типов / сопоставления с шаблоном, но синтаксис ускользнул от меня.Я также пробовал использовать :?оператор (динамические типовые испытания) и когда предложения в блоке сопоставления с шаблоном, но это по-прежнему приводит ко всевозможным ошибкам.

Поскольку я довольно новичок в этом языке, вполне возможно, что я пытаюсь сделать здесь что-то невозможное, поэтому, пожалуйста, дайте мне знать, если есть альтернативное решение.

Это было полезно?

Решение

Перегрузка обычно является ошибкой языков, основанных на выводе типов (по крайней мере, когда, как F #, система типов недостаточно мощна, чтобы содержать классы типов).Есть несколько вариантов, которые у вас есть в F#:

  • Используйте перегрузку для методов (членов типа), и в этом случае перегрузка работает так же, как и в других .Сетевые языки (вы можете однорангово перегружать участников, при условии, что вызовы можно отличать по количеству / типу параметров)
  • Используйте "встроенные", "^" и статические ограничения-члены для специальной перегрузки функций (это то, что большинство различных математических операторов, которые должны работать с int / float / etc.;синтаксис здесь странный, он мало используется отдельно от библиотеки F #)
  • Имитировать классы типов путем передачи дополнительного параметра dictionary-of-operations (это то, что INumeric делает в одной из библиотек F # PowerPack для обобщения различных математических алгоритмов для произвольных пользовательских типов)
  • Вернитесь к динамической типизации (передайте параметр 'obj', выполните динамический тест типа, выдайте исключение во время выполнения для неправильного типа).

Для вашего конкретного примера я бы, вероятно, просто использовал перегрузку метода:

type MathOps =
    static member sqrt_int(x:int) = x |> float |> sqrt |> int
    static member sqrt_int(x:int64) = x |> float |> sqrt |> int64

let x = MathOps.sqrt_int 9
let y = MathOps.sqrt_int 100L

Другие советы

Это работает:

type T = T with
    static member ($) (T, n:int  ) = int   (sqrt (float n))
    static member ($) (T, n:int64) = int64 (sqrt (float n))

let inline sqrt_int (x:'t) :'t = T $ x

Он использует статические ограничения и перегрузку, что приводит к поиску типа аргумента во время компиляции.

Статические ограничения автоматически генерируются в присутствии оператора (operator $ в данном случае), но это всегда может быть написано от руки:

type T = T with
    static member Sqr (T, n:int  ) = int   (sqrt (float n))
    static member Sqr (T, n:int64) = int64 (sqrt (float n))

let inline sqrt_int (x:'N) :'N = ((^T or ^N) : (static member Sqr: ^T * ^N -> _) T, x)

Подробнее об этом здесь.

Да, это можно сделать.Взгляните на этот поток hubFS.

В этом случае решением было бы:

let inline retype (x:'a) : 'b = (# "" x : 'b #)
let inline sqrt_int (n:'a) = retype (sqrt (float n)) : 'a

Предостережение:нет проверки типа во время компиляции.То есть. sqrt_int "blabla" компилируется нормально, но во время выполнения вы получите исключение FormatException .

Вот еще один способ, использующий проверки типов во время выполнения...

let sqrt_int<'a> (x:'a) : 'a = // '
    match box x with
    | :? int as i -> downcast (i |> float |> sqrt |> int |> box)
    | :? int64 as i -> downcast (i |> float |> sqrt |> int64 |> box)
    | _ -> failwith "boo"

let a = sqrt_int 9
let b = sqrt_int 100L
let c = sqrt_int "foo" // boom

Не хочу отвлекаться от уже предоставленных правильных ответов, но на самом деле вы можете использовать ограничения типа при сопоставлении с образцом.Синтаксис таков:

| :? type ->

Или, если вы хотите объединить проверку типов и приведение:

| :? type as foo ->
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top