int64 не поддерживает LanguagePrimitives.DivideByInt?

Почему int64 не поддерживает LanguagePrimitives.DivideByInt? Я подумал, что было бы вполне естественно написать что-то вроде этого:

let inline DivBy2 n = LanguagePrimitives.DivideByInt n 2
let res = DivBy2 100L

Но компилятор говорит, что int64 doesn't support the operator DivideByInt.

Я пытался обмануть с помощью:

type System.Int64 with 
    static member DivideByInt (n: System.Int64) (d: int) = n / (int64 d)

Но это не работает.

Что можно сделать, чтобы выполнить общее деление int64 на int?


person Dmitrii Lobanov    schedule 02.03.2012    source источник
comment
Я думаю, что было бы проще всего добавить это, перестроив FSharp.Core - код, который вам нужно изменить, находится примерно в строке 2300 из prim-types.fs.   -  person John Palmer    schedule 02.03.2012
comment
Да, мне интересно, почему нет поддержки int64. Я отправил запрос в fsbugs, чтобы понять их решение по этой проблеме.   -  person Dmitrii Lobanov    schedule 02.03.2012


Ответы (5)


Глядя на исходный код F #, тип int64 не включен в функцию DivideByInt, я не знаю, почему.

Вы можете определить другую общую функцию следующим образом:

open LanguagePrimitives
type DivExtension = DivExtension of int with
    static member inline (=>) (x             , DivExtension y) = DivideByInt x y
    static member        (=>) (x:int64       , DivExtension y) = x / (int64 y)
    static member        (=>) (x:DivExtension, DivExtension y) = x

let inline DivByInt x y = x => DivExtension y

Или вы можете даже скрыть исходную функцию DivideByInt:

let inline DivideByInt x y = x => DivExtension y

Обратите внимание, что вы также можете добавить больше перегрузок (например, для int), и в этом случае вам не нужна последняя «фиктивная» перегрузка, чтобы вывести правильную подпись.

person Gus    schedule 02.03.2012
comment
Зачем нужна последняя фиктивная перегрузка? - person Dmitrii Lobanov; 02.03.2012
comment
Потому что, если его убрать, вывод типов объединит обе оставшиеся перегрузки с int64. Вы можете использовать аннотации типов со всеми ограничениями, когда или просто добавить другую перегрузку, и она будет автоматически обобщена. - person Gus; 02.03.2012

Я получил ответ от Дона Сайма (по электронной почте fsbugs) на вопрос об отсутствии MutliplyByInt и ограниченной поддержке DivideByInt:

Ответ Дона:

Этот оператор существует для поддержки «Seq.averageBy» и т. д. Он представляет собой псевдоточное деление суммы на количество. Мы не расширяли механизм сверх того, что было необходимо для этого.

Похоже, я неправильно понял назначение этого механизма. Но я до сих пор не знаю, почему нет поддержки int64 для DivideByInt, это значит, что мы ограничены в универсальных операциях над типом int64. Возможно, я запутался, потому что int64 выглядит как примитивный тип, когда это не примитивный тип. А DivideByInt определен только для примитивных типов, поэтому для него нет поддержки.

person Community    schedule 08.03.2012

Как вы заметили, DivideByInt в основном существует для поддержки Seq.averageBy. Тот факт, что целочисленные типы не поддерживаются, имеет для меня смысл, поскольку среднее значение [1;2] должно быть 1.5, а не 1 (именно это даст вам реализация DivideByInt). Это заставляет вас преобразовывать ваши входные данные в числа с плавающей запятой, что дает вам ожидаемый ответ.

person kvb    schedule 08.03.2012
comment
О, ваш ответ заставил меня убедиться, что int также не поддерживает DivideByInt. Первоначальный вопрос был о том, почему int64 не поддерживается, когда поддерживается int. И оказывается, что ни один целочисленный тип не поддерживается. Спасибо! Теперь это действительно имеет смысл, просто ставит все на свои места! - person Dmitrii Lobanov; 08.03.2012

Можете ли вы определить это таким образом?

let inline DivBy2 n = 
  let one = LanguagePrimitives.GenericOne
  n / (one + one)
person Daniel    schedule 02.03.2012
comment
О, я разместил пример с DivBy2 просто для примера. Мне интересно, возможно ли в F # использовать int64, где есть ограничение DivideByInt. - person Dmitrii Lobanov; 02.03.2012

Я явно опоздал на вечеринку, но было бы интересно узнать, почему вы хотите создать функцию divBy2. Здесь есть две проблемы, и решения одной из них может быть достаточно, в зависимости от ваших потребностей.

Первая проблема в том, что нет LanguagePrimitives.GenericTwo. Это легко исправить, но решение имеет ограниченное применение, если вы хотите определить определенные функции деления для делителей, отличных от 2:

let inline divBy2 n =
    n / (LanguagePrimitives.GenericOne + LanguagePrimitives.GenericOne)

Чтобы меньше печатать, вы можете присвоить переменной LanguagePrimitives.GenericOne, что становится более полезным по мере увеличения величины вашего делителя:

let inline divBy4 n =
    let one = LanguagePrimitives.GenericOne
    let two = one + one
    n / (two + two)

Это решение также бесполезно, если вы хотите создать общую функцию. "Пользовательский" способ будет

let inline divBy divisor dividend = dividend / divisor

Мы можем использовать это с приложением частичной функции, чтобы вдвое сократить список байтов, например, так:

let halfBytes = [ 1uy .. 10uy ] |> List.map (divBy 2uy)

Но мы можем сделать лучше. Эта проблема относится ко всем некоммутативным операторам, включая вычитание. Чтобы обойти это, мы можем определить

let flip f a b = f b a

Это позволяет, например

let scaledInThousands = [ 0m .. 500m .. 3000m ] |> List.map (flip (/) 1000m)
let decrementedIntegers = [ 1 .. 10 ] |> List.map (flip (-) 1)

Если вы хотите, вы все равно можете определить функцию divBy:

let inline divBy n = flip (/) n
let halfInts = [ 1 .. 10 ] |> List.map (divBy 2)
let halfLongs = [ 1L .. 10L ] |> List.map (divBy 2L)
let fifthLongs = [ 1L .. 10L ] |> List.map (divBy 5L)
let oneThroughTenOverPi = [ 1.0 .. 10.0 ] |> List.map (divBy System.Math.PI)
person phoog    schedule 18.08.2014