代码之家  ›  专栏  ›  技术社区  ›  em70

范围A到B,其中A>B在F中#

f#
  •  7
  • em70  · 技术社区  · 15 年前

    我刚刚发现了一种我称之为F怪癖的东西,我想知道它是设计的还是错误的,如果是设计的,为什么会这样…… 如果编写的任何范围表达式的第一项大于第二项,则返回的序列为空。看看Reflector就可以看出这是设计出来的,但我真的找不到一个理由来解释为什么必须这样做。 复制它的一个例子是:

    
    [1..10] |> List.length
    [10..1] |> List.length
    

    第一个将打印出10,第二个将打印出0。 试验在F CTP 1.9.6.2中进行。

    编辑 :谢谢你提出了明确的范围,但还有一个案例(这就是激励我问这个问题的原因)是无法涵盖的。如果A和B是变量,尽管它们总是不同的,但没有一个总是大于另一个呢? 考虑到范围表达式在编译时似乎没有得到优化,如果a和b是int,那么确定步骤(未显式指定)的代码是否有充分的理由不允许负步骤?

    5 回复  |  直到 8 年前
        1
  •  12
  •   Brian    15 年前

    根据其他答案的建议,你可以

    [10 .. -1 .. 1] |> List.iter (printfn "%A")
    

    例如

    [start .. step .. stop]
    
        2
  •  3
  •   James Hugard    15 年前

    亚当·赖特-但你应该 要更改类型的绑定, 对你的行为有兴趣 喜欢(包括如果x>倒计时 Y)。

    将亚当的建议纳入代码:

    let (..) a b =
        if a < b then seq { a .. b }
                 else seq { a .. -1 .. b }
    
    printfn "%A" (seq { 1 .. 10 })
    printfn "%A" (seq { 10 .. 1 })
    

    这适用于int范围。请看一下(..)的源代码:您可能可以使用它来处理其他类型的范围,但不确定如何为特定类型获得-1的正确值。

        3
  •  3
  •   rmunn    8 年前

    当然,“应该”发生的是主观的。在我的头脑中,标准范围符号将[x..y]定义为所有大于或等于x且小于或等于y的元素的集合;如果是y<x,则定义为空集合。在这种情况下,我们需要求助于f规范。

    范围表达式expr1..expr2被计算为对重载运算符(..)的调用,该运算符的默认绑定是在microsoft.fsharp.core.operators中定义的。这将为给定的开始(expr1)和完成(expr2)值之间的值范围生成一个IEnumerable<gt;,增量为1。该运算符要求在具有适当签名的expr1静态类型上存在静态成员(..)(long name getrange)。

    范围表达式expr1..ExpR2…expr3作为对重载运算符(..)的调用进行计算。..)的默认绑定是在microsoft.fsharp.core.operators中定义的。这将使用expr2的增量为给定的start(expr1)和finish(expr3)值之间的值范围生成IEnumerable。该运算符要求在具有适当签名的expr1静态类型上存在静态成员(..)(long name getrange)。

    标准似乎没有定义……接线员(至少,我能找到)。但是,您应该能够更改您感兴趣的类型的绑定,以您喜欢的任何方式进行操作(包括如果x>y,则倒计时)。

        4
  •  2
  •   Jonas    15 年前

    在哈斯克尔,你可以写 [10, 9 .. 1] . 也许它在F(我没试过)中的作用是一样的?

    编辑:

    似乎f语法不同,可能是 [10..-1..1]

        5
  •  1
  •   Andrew Hare    15 年前

    范围通常(以支持它们的语言和框架)如下所示:

    low_value <to> high_value

    你能提出一个很好的论据,为什么一个区间应该能够以不同的方式表达吗?既然您请求的是一个从高到低的数字范围,那么结果范围中是否没有成员呢?