【问题标题】:Co-prime values in F#F#中的互质值
【发布时间】:2016-10-21 15:43:35
【问题描述】:

我是一个 F# 新手,正在处理一个琐碎的问题。如何检查两个整数是否互质?我发现this pythonic 方法非常有趣,而且,恕我直言,优雅。我正在尝试用 F# 翻译它,但没有运气。我想这主要是由于我的经验不足。

无论如何,这是我迄今为止“最好的”尝试:

let prime (x, y) =                                          
  if y <> 0 then
      (x, y) <| (y, x % y)
  else 
      x;; 

它应该导致,即在

prime 23 13;;
- : bool = true

显然,它不起作用。在 F# 中解决此类问题的最佳方法是什么?我来自 R 编程,这需要完全不同的思维方式。

【问题讨论】:

    标签: python f#


    【解决方案1】:

    几乎是直接翻译的python代码链接。

    首先我们需要定义一个gcd 函数,使用递归作为“循环构造”而不是python while(FP 更“面向递归”)

    let rec gcd = function
      | x, 0 -> x
      | x, y -> gcd (y, x % y)
    

    剩下的就是 coprime 函数来定义哪个可以在 pointfree 样式中轻松完成,方法是组合前面的 gcd 函数,部分应用与 1 的相等性

    let coprime = gcd >> (=) 1
    

    功能相同:

    let coprime (x, y) = gcd (x, y) = 1
    

    除此之外,我们可以通过一些调整使代码更通用(关于数字类型),尽管我不确定这是否值得
    (例如,在操作 bigint 时可能更喜欢使用BigInteger.GreatestCommonDivisor

    open LanguagePrimitives
    
    let inline gcd (x, y) =
      // we need an helper because inline and rec don't mix well
      let rec aux (x, y) =
        if y = GenericZero
        then x
        else aux (y, x % y)
      aux (x, y)
    
    // no pointfree style, only function can be inlined not values
    let inline coprime (x, y) = gcd (x, y) = GenericOne
    

    来自@Henrik Hansen 的答案是一个更新版本,计算出active pattern 以提高可读性并提取常见行为

    let (|LT|EQ|GT|) (x, y) =
      if x < y then LT
      elif x = y then EQ
      else GT
    
    let areCoPrimes x y =
      let rec aux (x, y) =
        match x, y with
        | 0, _ | _, 0 -> false
        | LT          -> aux (x, y - x)
        | EQ          -> x = 1
        | GT          -> aux (x - y, y)
      aux (abs x, abs y)
    

    【讨论】:

    • 我很惊讶。它甚至是美丽的。谢谢!
    【解决方案2】:

    仅用于运动:这里是使用欧几里得算法的减法版本的版本。不像 Sehnsuchts 使用除法风格那样优雅,并且可能效率不高:

    let rec areCoPrimes a b =
        match a, b with
        | a, b when a < 0 -> areCoPrimes -a b
        | a, b when b < 0 -> areCoPrimes a -b
        | 0, b  -> false
        | a, 0 -> false
        | a, b when a = b -> a = 1
        | a, b when a > b -> areCoPrimes (a - b) b
        | a, b when a < b -> areCoPrimes a (b - a)
    

    欧几里得肉是最后三个匹配,而前四个处理小于或等于零的值。

    【讨论】:

    • 我很难切换到这种编程范式,因此欢迎提供任何示例,谢谢!
    • 可以使用内部辅助函数(它采用 args 的绝对值)并使用主动模式来简化this pastebin的可读性
    • @Sehnsucht:很好的链接。我的第一次尝试有点像没有主动模式的那样,而且并不漂亮。但是主动模式对此有所帮助。如果它是你的 pastebin,那么用它更新你的答案。
    猜你喜欢
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    相关资源
    最近更新 更多