gpt4 book ai didi

用于 Euler 项目 #2 的 Scala 无形代码

转载 作者:行者123 更新时间:2023-12-04 12:06:36 25 4
gpt4 key购买 nike

我已经开始着手解决 Project Euler Problem #2 的 Shapeless 解决方案.

我可以将所有偶数的谎言加在一起,直到 Nth即使是使用此代码的人:

import shapeless._, nat._, ops.nat.Sum

trait Fibonacci[N <: Nat] { type Out <: Nat }

object Fibonacci {
type Aux[N <: Nat, Out0 <: Nat] = Fibonacci[N] { type Out = Out0 }

def apply[N <: Nat](i: Nat)(implicit fib: Aux[i.N, N], n: Witness.Aux[N]):N = n.value

implicit val fib0 = new Fibonacci[_0] { type Out = _2 }
implicit val fib1 = new Fibonacci[_1] { type Out = _3 }

implicit def fibN[I <: Nat, L <: Nat, M <: Nat](implicit l: Aux[I, L],
m: Aux[Succ[I], M],
sum: Sum[L, M]) =
new Fibonacci[Succ[Succ[I]]] { type Out = sum.Out }
}

trait Fibs[N <: Nat] { type Out <: Nat }

object Fibs {
type Aux[N <: Nat, Out0 <: Nat] = Fibs[N] { type Out = Out0 }

def apply[N <: Nat](i: Nat)(implicit fibs: Aux[i.N, N], n: Witness.Aux[N]):N = n.value

implicit def fibs0(implicit f: Fibonacci[_0]) = new Fibs[_0] { type Out = f.Out }

implicit def fibsN[N <: Nat, R <: Nat, Z <: Nat](implicit fib: Fibonacci.Aux[Succ[Succ[Succ[N]]], R],
fibs: Aux[N, Z],
sum: Sum[R, Z]) =
new Fibs[Succ[N]] {
type Out = sum.Out
}
}

现在我可以这样做:
val (evenFibs0, evenFibs1) = (Fibs(0), Fibs(1))
typed[_2](evenFibs0)
typed[_10](evenFibs1)

这就是我得到所有偶数的方法:我从序列 2, 3, ... 开始,每三个斐波那契数求和。

现在,我被困住了。我想要类似于 takeWhile 的功能,所以我可以编写一个接受 limit 的函数并返回条款不超过该限制的偶数 fib 的总和。有任何想法吗?

这是我迄今为止所尝试的努力:
trait EvenFibsWithLimit[N <: Nat, M <: Nat] { type Out <: Nat }

trait LowPriorityFibs3 {
type Aux[N <: Nat, M <: Nat, Out0 <: Nat] = EvenFibsWithLimit[N, M] { type Out = Out0 }

implicit def fibs0[M <: Nat] = new EvenFibsWithLimit[_0, M] { type Out = _0 }

implicit def fibsGT[N <: Nat, M <: Nat, O <: Nat](implicit f: EvenFibsWithLimit[N, M],
fib: Fibs.Aux[N, O],
l: ops.nat.LT[M, O]) = f
}

object EvenFibsWithLimit extends LowPriorityFibs3 {
def apply[N <: Nat, O <: Nat](limit: Nat)(implicit fibs: Aux[N, limit.N, O],
o: Witness.Aux[O]): O = o.value

implicit def fibsN[N <: Nat, M <: Nat, O <: Nat](implicit f: EvenFibsWithLimit[N, M],
f2: Fibs.Aux[Succ[N], O],
d: ops.nat.Diff[M, O]) =
new EvenFibsWithLimit[Succ[N], d.Out] {
type Out = O
}
}

这个想法是通过输出递归地减去限制,直到输出小于限制。我绝对能闻到有什么东西坏了。我认为我不需要 Diff根本......我也尝试了一些其他的变化,但我一直被卡住。当我编译时,我收到错误 diverging implicit expansion for fibsN.
编辑:

我在想也许我可以构建一个 HList我的 Fibs ,并使用 Selector使用谓词类型类来模拟 takeWhile .想法?

最佳答案

我发现解决此类问题的最佳方法是在思考我需要跟踪的信息的同时逐步遍历自然数。

在纸上,我会使用这样的东西:

N  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
C 1 2 3 3 5 5 5 8 8 8 8 8 13 13 13
P 1 1 2 2 3 3 3 5 5 5 5 5 8 8 8
L 0 2 2 2 2 2 2 10 10 10 10 10 10 10 10

这里 C跟踪斐波那契数列中的当前数字——即小于或等于 N 的最大的一个. P是之前的斐波那契数,而 L是我们目前看到的偶数的当前总和。

我们可以把它翻译成一个类型类:
import shapeless._, ops.nat.{ Mod, Sum }, nat.{ _0, _1, _2 }

trait EvenFibs[N <: Nat] {
type L <: Nat
type C <: Nat
type P <: Nat
}

现在我们需要处理四种情况。首先,我将给出需要具有最低优先级才能获得正确的隐式分辨率的那个:
trait LowPriorityEvenFibs {
type Aux[N <: Nat, L0 <: Nat, C0 <: Nat, P0 <: Nat] = EvenFibs[N] {
type L = L0
type C = C0
type P = P0
}

implicit def ef3[N <: Nat](implicit
ef: EvenFibs[N]
): Aux[Succ[N], ef.L, ef.C, ef.P] = new EvenFibs[Succ[N]] {
type L = ef.L
type C = ef.C
type P = ef.P
}
}
Succ[N]就是这种情况不是斐波那契数。它不需要我们更新我们正在跟踪的任何值。下一个案例稍微复杂一点:
trait MidPriorityEvenFibs extends LowPriorityEvenFibs {
implicit def ef2[N <: Nat, L0 <: Nat, PP <: Nat, P0 <: Nat](implicit
ef: Aux[N, L0, P0, PP],
sum: Sum.Aux[PP, P0, Succ[N]]
): Aux[Succ[N], L0, Succ[N], P0] = new EvenFibs[Succ[N]] {
type L = L0
type C = Succ[N]
type P = P0
}
}
Succ[N]就是这种情况是奇数斐波那契数。在这种情况下,我们需要更新 CP ,但不是 L .

我们的最后 Succ[N]案例是 Succ[N]是偶数斐波那契数。我将在这里给出基本案例:
object EvenFibs extends MidPriorityEvenFibs {
implicit def ef0: Aux[_0, _0, _1, _1] = new EvenFibs[_0] {
type L = _0
type C = _1
type P = _1
}

implicit def ef1[N <: Nat, L <: Nat, PP <: Nat, P0 <: Nat](implicit
ef: Aux[N, L, P0, PP],
sum: Sum.Aux[PP, P0, Succ[N]],
mod: Mod.Aux[Succ[N], _2, _0],
current: Sum[Succ[N], L]
): Aux[Succ[N], current.Out, Succ[N], P0] = new EvenFibs[Succ[N]] {
type L = current.Out
type C = Succ[N]
type P = P0
}

def apply[N <: Nat](implicit ef: EvenFibs[N]): Aux[N, ef.L, ef.C, ef.P] = ef
}

最后,我们可以定义一个帮助类,它可以更容易地检查我们的工作:
class ComputeHelper[N <: Nat] {
def value[L <: Nat, C <: Nat, P <: Nat](implicit
ef: EvenFibs.Aux[N, L, C, P],
wit: Witness.Aux[L]
): L = wit.value
}

def compute[N <: Nat]: ComputeHelper[N] = new ComputeHelper[N]

进而:
test.typed[_0](compute[_0].value)
test.typed[_0](compute[_1].value)
test.typed[_2](compute[_2].value)
test.typed[_2](compute[nat._3].value)
test.typed[_2](compute[nat._4].value)
test.typed[_2](compute[nat._5].value)
test.typed[_2](compute[nat._6].value)
test.typed[_2](compute[nat._7].value)
test.typed[nat._10](compute[nat._8].value)
test.typed[nat._10](compute[nat._9].value)

最后一行在我的机器上编译大约需要 20 秒,但它有效。

关于用于 Euler 项目 #2 的 Scala 无形代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31615371/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com