3

Интересно, почему F-Sharp не поддерживает бесконечность.F-Sharp (F #) нетипизированная бесконечность

Это будет работать в Рубине (но не в F #):

let numbers n = [1 .. 1/0] |> Seq.take(n) 

-> System.DivideByZeroException: Пытались делить на ноль.

Я могу написать такую ​​же функциональность во многом сложным образом:

let numbers n = 1 |> Seq.unfold (fun i -> Some (i, i + 1)) |> Seq.take(n) 

-> работает

Однако я думаю, что первый из них будет гораздо более ясным. Я не могу найти простой способ использовать динамически типизированную бесконечность в F #. Существует бесконечность ключевое слово, но это поплавок:

let a = Math.bigint +infinity;; 

System.OverflowException: BigInteger не может представлять бесконечность. в System.Numerics.BigInteger..ctor (двойное значение) на $ FSI_0045.main @() остановлен из-за ошибки


Edit:. Также это похоже на работу в итерации:

+0

Является ли он выполнением целочисленной или с плавающей точкой арифметики? У этих двух есть совершенно разные понятия бесконечности. –

+0

Это не работает в Ruby. Infinity - это значение с плавающей запятой в Ruby, поэтому вам нужно будет делать деление с плавающей запятой - 1..1.0/0. – Chuck

+0

В этом конкретном случае «пусть числа n = seq {1 .. n}» могут быть самыми простыми ... –

ответ

8

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

Во-вторых, нет значения бесконечности в Int32. Только MaxValue. В Double есть положительная и отрицательная бесконечность.

Собирает вместе, это работает:

let numbers n = seq { 1. .. 1./0. } |> Seq.take(n) 

Я чувствую, однако Seq.initInfinite является лучшим вариантом. Этот код выглядит странно для меня. (Или, по крайней мере, используйте Double.PositiveInfinity вместо 1./0.)

На первый взгляд, хорошим вариантом на языке будет оператор бесконечного диапазона, например, в haskell: seq {1 ..} Проблема заключается в том, что он будет работать только для seq, поэтому я полагаю, что дополнительная работа для поддержки операторов постфикса не стоит того, чтобы использовать эту функцию.

Нижняя линия: на мой взгляд, используйте Seq.initInfinite.

+1

Поскольку Seq.initInfinite базируется в Int32, он должен для любой практической цели быть эквивалентен «seq {1 .. System.Int32.MaxValue}». Используя эту конструкцию, никто не обманывается, полагая, что на самом деле задействована какая-то неумение. Я бы рекомендовал это вместо этого. - Или развернутый подход - при работе с bigints ... –

+0

@Johan: Я чувствую, что Seq.initInfinite лучше работает с типом вывода - тип полученного seq должен быть выведен автоматически, тогда как с {1..Int32.MaxValue} вам нужен вызов некоторой константы. Таким образом, это может быть более близкое решение первоначального вопроса. Но действительно, бесконечность в initInfinite является неправильным. –

3

Я думаю, что это лучшее решение для бесконечных диапазонов в F #; пометив функцию inline, мы лучше, чем «динамически типизированная бесконечность», получаем структурно типизированные бесконечные диапазоны (работает с int32, int64, bigint, ... любым типом, который имеет статический член +, который принимает два аргумента своего типа и возвращает значение своего собственного типа):

let inline infiniteRange start skip = 
    seq { 
     let n = ref start 
     while true do 
      yield n.contents 
      n.contents <- n.contents + skip 
    } 

//val inline infiniteRange : 
// ^a -> ^b -> seq< ^a> 
// when (^a or ^b) : (static member (+) : ^a * ^b -> ^a) 
Смежные вопросы