F-Sharp (F #) нетипизированная бесконечность

Интересно, почему F-Sharp не поддерживает бесконечность?

Это будет работать в Ruby (но не в 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 (Double value) в. $ FSI_0045.main @ () остановлен из-за ошибки


Изменить: также это, кажется, работает в итерации:

let numbers n = Seq.initInfinite (fun i -> i+1) |> Seq.take(n)
13.10.2009 08:03:31
Это целочисленная или арифметика с плавающей точкой? У них совершенно разные понятия бесконечности.
Josh Lee 13.10.2009 08:07:13
Это не работает в Ruby. Infinity также является значением с плавающей точкой в ​​Ruby, поэтому вам нужно выполнить деление с плавающей точкой - 1..1.0 / 0.
Chuck 13.10.2009 08:12:01
В этом конкретном случае «пусть числа n = seq {1 .. n}» могут быть самыми простыми ...
Johan Kullbom 13.10.2009 08:46:09
Йохан, Seq.take (n) отсутствует в моем собственном коде, он просто здесь для демонстрационных целей. :-)
Tuomas Hietanen 13.10.2009 08:57:38
Да, я догадался, что это так ... :) Мне кажется, что вопрос бесконечности весьма интересен в контексте программирования - и я считаю, что у вас часто есть естественный предел ... - но это другой вопрос ...
Johan Kullbom 13.10.2009 09:26:08
2 ОТВЕТА
РЕШЕНИЕ

Прежде всего, списки 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.

8
13.10.2009 09:30:13
Поскольку Seq.initInfinite основан на Int32, для любых практических целей он должен быть эквивалентен 'seq {1 .. System.Int32.MaxValue}'. Вместо этого, используя эту конструкцию, никто не обманывается, полагая, что любая безграничность действительно вовлечена. Я бы порекомендовал это вместо. - Или развернутый подход - когда имеешь дело с bigints ...
Johan Kullbom 13.10.2009 09:42:13
@Johan: Мне кажется, что Seq.initInfinite лучше работает с выводом типа - тип результирующего seq должен выводиться автоматически, тогда как для {1..Int32.MaxValue} вам нужен вызов некоторой константы. Так что это может быть более близким решением к первоначальному вопросу. Но на самом деле, бесконечное в initInfinite является неправильным.
Kurt Schelfthout 13.10.2009 11:57:38

Я думаю, что следующее является лучшим решением для бесконечных диапазонов в 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)
3
21.11.2010 22:34:09