Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 创建中间值时,我应该存储它吗?_F#_Functional Programming_Primes_Factorization - Fatal编程技术网

F# 创建中间值时,我应该存储它吗?

F# 创建中间值时,我应该存储它吗?,f#,functional-programming,primes,factorization,F#,Functional Programming,Primes,Factorization,我正在努力学习F#,所以我访问了,目前正在学习 13195的主要因素是5,7, 13和29 最大的素数是多少 数字600851475143的系数 需要考虑的一些事项: 我的首要任务是学习良好的功能性习惯 我的第二个优先事项是我希望它是快速和高效的 在下面的代码中,我已经标记了这个问题所涉及的部分 let isPrime(n:int64) = let rec check(i:int64) = i > n / 2L or (n % i <> 0L &am

我正在努力学习F#,所以我访问了,目前正在学习

13195的主要因素是5,7, 13和29

最大的素数是多少 数字600851475143的系数

需要考虑的一些事项:

  • 我的首要任务是学习良好的功能性习惯
  • 我的第二个优先事项是我希望它是快速和高效的 在下面的代码中,我已经标记了这个问题所涉及的部分

    let isPrime(n:int64) = 
        let rec check(i:int64) = 
            i > n / 2L or (n % i <> 0L && check(i + 1L))
        check(2L) 
    
    let greatestPrimeFactor(n:int64) =
        let nextPrime(prime:int64):int64 = 
            seq { for i = prime + 1L to System.Int64.MaxValue do if isPrime(i) then yield i }  
            |> Seq.skipWhile(fun v -> n % v <> 0L) 
            |> Seq.hd
        let rec findNextPrimeFactor(number:int64, prime:int64):int64 =
            if number = 1L then prime else 
                //************* No variable
                (fun p -> findNextPrimeFactor(number / p, p))(nextPrime(prime))    
                //*************               
                //************* Variable
                let p = nextPrime(prime)
                findNextPrimeFactor(number / p, p) 
                //*************
        findNextPrimeFactor(n, 2L) 
    
    let isPrime(n:int64)=
    让rec检查(i:int64)=
    i>n/2L或(n%i 0L和检查(i+1L))
    检查(2L)
    设greatestPrimeFactor(n:int64)=
    让NextTime(素数:int64):int64=
    seq{for i=prime+1L to System.Int64.MaxValue do如果isPrime(i)则产生i}
    |>轻快地滑行(乐趣->n%v 0L)
    |>Seq.hd
    让rec查找dnextprimefactor(数字:int64,素数:int64):int64=
    如果数字=1L,则为其他值加素数
    //*************无变量
    (乐趣p->findNextPrimeFactor(数字/p,p))(下一次(素数))
    //*************               
    //*************变数
    设p=nexttime(prime)
    findNextPrimeFactor(编号/p,p)
    //*************
    findNextPrimeFactor(n,2L)
    
    更新

    根据一些反馈,我将代码重构为快10倍

    module Problem3
    
    module private Internal =
        let execute(number:int64):int64 = 
            let rec isPrime(value:int64, current:int64) = 
                current > value / 2L or (value % current <> 0L && isPrime(value, current + 1L))   
            let rec nextPrime(prime:int64):int64 = 
                if number % prime = 0L && isPrime(prime, 2L) then prime else nextPrime(prime + 1L)       
            let rec greatestPrimeFactor(current:int64, prime:int64):int64 =
                if current = 1L then prime else nextPrime(prime + 1L) |> fun p -> greatestPrimeFactor(current / p, p)
            greatestPrimeFactor(number, 2L)
    
    
    let execute() = Internal.execute(600851475143L)
    
    模块问题3
    模块专用内部=
    让我们执行(编号:int64):int64=
    let rec isPrime(值:int64,当前值:int64)=
    电流>值/2L或(值%current 0L&&isPrime(值,电流+1L))
    let rec nexttime(prime:int64):int64=
    如果数字%prime=0L&&isPrime(prime,2L),则在下一个时间为else(prime+1L)
    let rec greatestPrimeFactor(当前:int64,素数:int64):int64=
    如果当前值=1L,则为下一次的其他值加素数(素数+1L)|>fun p->greatestPrimeFactor(当前值/p,p)
    最大优先因子(编号,2L)
    let execute()=内部.execute(600851475143L)
    
    更新

    我要感谢大家的建议。这个最新版本是我收到的所有建议的汇编

    module Problem3
    
    module private Internal =
        let largestPrimeFactor number = 
            let rec isPrime value current = 
                current > value / 2L || (value % current <> 0L && isPrime value (current + 1L))   
            let rec nextPrime value =
                if number % value = 0L && isPrime value 2L then value else nextPrime (value + 1L) 
            let rec find current prime =
                match current / prime with
                | 1L -> prime
                | current -> nextPrime (prime + 1L) |> find current
            find number (nextPrime 2L)            
    
    let execute() = Internal.largestPrimeFactor 600851475143L
    
    模块问题3
    模块专用内部=
    设最大PrimeFactor数=
    让rec isPrime值当前=
    当前>值/2L | |(值%current 0L&&isPrime值(当前+1L))
    让rec nexttime值=
    如果数字%value=0L&&isPrime值2L,则值else nextPrime(值+1L)
    让rec找到当前素数=
    将当前/素数与
    |1L->prime
    |当前->下一次时间(初始值+1L)|>查找当前值
    查找号码(下一次2L)
    let execute()=Internal.largestPrimeFactor 600851475143L
    
    变量p实际上是名称绑定,而不是变量。使用名称绑定是一种不错的风格。而且它更具可读性。
    nexttime
    的惰性风格很好,它实际上在整个程序中只对每个数字进行一次初始测试

    我的解决方案

    let problem3 = 
        let num = 600851475143L
        let rec findMax (n:int64) (i:int64) =
            if n=i || n<i then
                n
            elif n%i=0L then
                findMax (n/i) i
            else
                findMax n (i+1L)
        findMax num 2L
    

    我认为带有临时绑定的代码更容易阅读。创建一个匿名函数,然后像在另一种情况下那样立即将其应用于一个值,这是非常罕见的。如果您真的想避免使用临时值,我认为在F#中最惯用的方法是使用
    (|>)
    操作符将值导入匿名函数,但我仍然认为这不太可读。

    关于“良好的函数习惯”或更好的实践,我看到了三件小事。在序列中使用收益率比仅仅过滤要难一些。类型推断语言中不必要的类型注释会导致重构困难,并使代码更难阅读。如果您觉得很困难,请不要过火,尝试删除每个类型注释。最后,生成一个lambda函数,该函数只接受一个值作为临时变量,这会降低可读性

    就个人风格而言,我更喜欢更多的空格,当数据分组在一起有意义时,只使用元组参数

    我会这样写你的原始代码

    let isPrime n = 
        let rec check i = 
            i > n / 2L || (n % i <> 0L && check (i + 1L))
        check 2L
    
    let greatestPrimeFactor n =
        let nextPrime prime = 
            seq {prime + 1L .. System.Int64.MaxValue}
            |> Seq.filter isPrime
            |> Seq.skipWhile (fun v -> n % v <> 0L) 
            |> Seq.head
    
        let rec findNextPrimeFactor number prime =
            if number = 1L then 
                prime 
            else 
                let p = nextPrime(prime)
                findNextPrimeFactor (number / p) p
    
        findNextPrimeFactor n 2L
    
    让iPrime n=
    让rec检查i=
    i>n/2L | |(n%i 0L&检查(i+1L))
    检查2L
    设最大主因子n=
    设NextTime素数=
    seq{prime+1L..System.Int64.MaxValue}
    |>Seq.filter iPrime
    |>轻快地滑行(乐趣->n%v 0L)
    |>序号头
    让rec查找dnextprimefactor数prime=
    如果数量=1L,则
    首要的
    其他的
    设p=nexttime(prime)
    findNextPrimeFactor(编号/p)p
    findNextPrimeFactor n 2L
    

    更新后的代码最适合您的方法。你必须使用一种不同的算法,比如尹朱的答案来加快速度。我编写了一个测试来检查F#是否使“check”函数尾部递归,并且确实如此。

    函数编程在实践中变得更容易、更自动化,所以如果第一次尝试时没有完全正确,不要担心

    考虑到这一点,让我们以您的示例代码为例:

    let rec findNextPrimeFactor(number:int64, prime:int64):int64 =
            if number = 1L then prime else 
                //************* No variable
                (fun p -> findNextPrimeFactor(number / p, p))(nextPrime(prime))    
                //*************               
                //************* Variable
                let p = nextPrime(prime)
                findNextPrimeFactor(number / p, p) 
                //*************
    
    您的
    no variable
    版本很奇怪,不要使用它。我喜欢带有显式let绑定的版本

    另一种写作方式是:

    nextPrime(prime) |> fun p -> findNextPrimeFactor(number / p, p)
    
    这样写是可以的,偶尔也有用,但还是有点奇怪。大多数情况下,我们使用
    |>
    来转换值,而不需要为变量命名(以“无点”样式)。尝试预测您的函数将如何使用,如果可能,重新编写它,以便可以在不显式声明变量的情况下与管道操作符一起使用。例如:

    let rec findNextPrimeFactor number prime =
        match number / prime with
        | 1L -> prime
        | number' -> nextPrime(prime) |> findNextPrimeFactor number'
    
    没有其他命名参数:)


    好的,现在我们已经解决了这个问题,让我们看看您的
    isPrim
    
    let rec findNextPrimeFactor number prime =
        match number / prime with
        | 1L -> prime
        | number' -> nextPrime(prime) |> findNextPrimeFactor number'
    
    let isPrime(n:int64) = 
        let rec check(i:int64) = 
            i > n / 2L or (n % i <> 0L && check(i + 1L))
        check(2L) 
    
    let isPrime n = seq { 2L .. n / 2L } |> Seq.exists (fun i -> n % i = 0L) |> not
    
    let maxFactor n =
        seq { 2L .. n - 1L }                        // test inputs
        |> Seq.filter isPrime                       // primes
        |> Seq.filter (fun x -> n % x = 0L)         // factors
        |> Seq.max                                  // result