繁体   English   中英

f# 连接对象列表

[英]f# concatenate list of objects

type Googol = {
    number : float
    power : float
    result : float
}

let generatePowers (n:float) : list<Googol> = 
    let rec powerInner (n:float) (p:float) (acc : list<Googol>) = 
        match n with
        | p when p <= 1.0 -> acc
        | p when p > 1.0 -> powerInner n (p-1.0) ([{ number=n; power=p; result=n**p}]@acc)
    let rec numberInner (n:float) (acc : list<Googol>) = 
        match n with 
        | n when n <=1.0 -> acc
        | n when n >1.0 -> numberInner (n-1.0) ((powerInner n [])@acc)
    numberInner n []

ProjectEuler.fsx(311,50): error FS0001: This expression was expected to have type
    'Googol list'
but here has type
    'Googol list -> Googol list'

我正在尝试解决这个问题-> https://projecteuler.net/problem=56 | 但为此我需要生成低于 n < 100 的幂。当我尝试连接[{ number=n; power=p; result=n**p}]@acc [{ number=n; power=p; result=n**p}]@acc [{ number=n; power=p; result=n**p}]@acc这些列表我得到了上面的错误。 请解释为什么错误显示'Googol list -> Googol list'在 function 中,我是否将 function 作为参数插入 ZC1C425268E68385D1AB4074C17A94 或实际插入列表之后。 @是function吗?

您在这里缺少一个参数:

| n when n >1.0 -> numberInner (n-1.0) ((powerInner n [])@acc)
                                         ^^^^^^^^^^^^^^^
                                               here

powerInner用三个参数定义,但你只传递了两个。

在 F# 中,传递比定义少的参数在技术上并不违法。 如果这样做,结果将是“预期”剩余参数的 function。 例如:

let f : int -> int -> string

let x = f 42
// Here, x : int -> string

let y = x 5
// Here, y : string

因此,在您的情况下,省略最后一个参数会使结果类型Googol list -> Googol list ,然后结果与 operator @预期的类型Googol list不兼容。 这是编译器在错误消息中告诉您的内容。

这看起来像是家庭作业或练习,所以首先我会给出一些提示以继续前进。 最后,我将展示一个似乎可以工作的版本,然后告诉我将如何解决这个问题。

任务是找到数字a ** b ,对于ab小于 100,其自身数字的总和最大。

第一个问题是 float 不会给我们a ** b的所有数字,所以这种类型对解决问题没有用处。 为了解决这个问题,我们转向 BigInteger 类型和 BigInteger.Pow function。 然后如果我们运行以下代码段,我们会得到一个 1 后跟 200 个零,就像它在问题描述中所说的那样。

let x: bigint = BigInteger.Pow (100I, 100)
let x: string = string x
printfn "s=%s" x

要获得有用的结果,请更改 Googol 类型,使其使用bigint ,但power应该是int

为什么 function generatePowers里面的函数powerInnernumberInner 这似乎没有特定目的,因此我建议将它们移出以使其更清楚。

function powerInnern进行匹配,但随后将结果命名为p ,这会隐藏p参数,使其未被使用。 好的,这里的意图可能是匹配p而不是n ,所以只需修复它,然后p参数的阴影就很好了。

首先在<= 1上然后在> 1上的测试会导致不完整的匹配。 如果第一行检查数字是否小于或等于 1,则在下一行中它必须大于 1。 因此,只需使用n ->而无需when修复它。 我还怀疑您想测试<= 0而不是 1。

这个

[{ number=n; power=p; result=n**p}]@acc

可以只是

{ number=n; power=p; result=n**p } :: acc

和这里

(powerInner n [])

我怀疑你只需要一个功率的起始值,即 99

(powerInner n 99 [])

剧透警告

经过一番修补,这就是我最终得到的,它似乎打印出一个有用的数字列表。 请注意,为了不通过打印输出运行所有 99 x 99 结果,我在这里使用低起始数字 3 和 5 进行倒计时,所以我们得到一些简单的打印输出,我们可以研究分析。

type Googol = { number: bigint; power: int; result: bigint }

let rec powerInner (n: bigint) (p: int) (acc: Googol list) =
    match p with
    | p when p <= 0 -> acc
    | p ->
        let newNumber = { number = n; power = p; result = n ** p }
        printfn "newNumber=%0A" newNumber
        powerInner n (p - 1) (newNumber :: acc)

let rec numberInner (n: bigint) (acc: Googol list) =
    match n with
    | n when n <= 0I -> acc
    | n -> numberInner (n - 1I) ((powerInner n 5 []) @ acc)

let generatePowers (n: bigint) : Googol list =
    numberInner n []

let powers = generatePowers 3I

我不确定这个解决方案是否正确。 无论如何,我会做不同的事情。

我会简单地在两个循环中循环 a 和 b,一个在另一个循环中。 对于每个a ** b我会将结果转换为字符串,然后对字符串的数字求和。 然后我会简单地使用一个可变的来保持最高的结果。 使用其中一个花哨的 List 函数可以以更实用的方式实现相同的目的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM