我是一个处理琐碎问题的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编程,需要完全不同的思维形式。
答案 0 :(得分:8)
几乎是链接的python代码的直接翻译。
首先,我们需要使用递归定义{{1}}函数作为&#34;循环构造&#34;而不是python而(FP更多&#34;面向递归&#34;)
gcd
只留下let rec gcd = function
| x, 0 -> x
| x, y -> gcd (y, x % y)
函数来定义哪些可以在 pointfree样式中轻松完成,方法是将先前的coprime
函数与1的相等部分应用程序组合在一起
gcd
功能与以下相同:
let coprime = gcd >> (=) 1
除此之外我们可以通过一些调整来使代码更通用(关于数字类型),虽然我不确定它是否值得
(例如,当操纵bigint时,人们可能更喜欢使用let coprime (x, y) = gcd (x, y) = 1
)
BigInteger.GreatestCommonDivisor
从@Henrik Hansen回答这里是一个更新版本,用active pattern来简化可读性并提取常见行为
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
答案 1 :(得分:6)
仅适用于这项运动:这是使用欧几里得算法的减法版本的版本。不像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)
欧几里德肉是最后三场比赛,而前四场则是小于或等于零的值。