我找到了一个很好的哈克尔解决方案(source)来生成Hofstadter sequence:
hofstadter = unfoldr (\(r:s:ss) -> Just (r, r+s:delete (r+s) ss)) [1..]
现在,我也试图在F#中编写这样的解决方案。不幸的是(我对F#并不熟悉)到目前为止我没有成功。
我的问题是,当我在F#中使用sequence
时,似乎无法删除元素(就像在haskell解决方案中完成的那样)。
允许删除元素的其他数据结构(如arrays
,list
或set
)不会生成无限序列,而只会对某些元素进行操作。
所以我的问题:在F#中是否可以生成无限序列,其中元素被删除?
到目前为止我尝试过的一些东西:
无限的数字序列:
let infinite =
Seq.unfold( fun state -> Some( state, state + 1) ) 1
Hofstadter序列 - 无效,因为没有del
关键字且语法错误更多
let hofstadter =
Seq.unfold( fun (r :: s :: ss) -> Some( r, r+s, del (r+s) ss)) infinite
我考虑过使用Seq.filter
,但也找不到解决方案。
答案 0 :(得分:5)
我认为你需要的不仅仅是序列上的delete
函数。您的示例需要在无限集合上进行模式匹配,该序列不支持。
Haskell列表的F#对应物是来自F#PowerPack的LazyList。 LazyList也可能是无限的,它支持模式匹配,这有助于您轻松实现delete
。
这是一个忠实的翻译:
open Microsoft.FSharp.Collections.LazyList
let delete x xs =
let rec loop x xs = seq {
match xs with
| Nil -> yield! xs
| Cons(x', xs') when x = x' -> yield! xs'
| Cons(x', xs') ->
yield x'
yield! loop x xs'
}
ofSeq (loop x xs)
let hofstadter =
1I |> unfold (fun state -> Some(state, state + 1I))
|> unfold (function | (Cons(r, Cons(s, ss))) ->
Some(r, cons (r+s) (delete (r+s) ss))
| _ -> None)
|> toSeq
这里有一些有趣的事情:
delete
以确保函数是尾递归的。非尾递归版本应该很容易。BigInteger
;如果您不需要太多元素,则使用int
和Seq.initInfinite
会更有效。None
的案例,以确保详尽的模式匹配。LazyList
转换为序列。它提供了与.NET集合更好的互操作性。在序列上实现delete
更加丑陋。如果您感到好奇,请查看Remove a single non-unique value from a sequence in F#以供参考。
答案 1 :(得分:4)
pad的解决方案很不错,但可能由于实现LazyList
的方式,堆栈溢出介于3-4K数字之间。出于好奇心的缘故,我编写了一个围绕生成函数(unit -> 'a
)构建的版本,该函数被重复调用以获取下一个元素(以解决IEnumerable
的笨拙)。我能够获得前10K的数字(除此之外没有尝试过)。
let hofstadter() =
let delete x f =
let found = ref false
let rec loop() =
let y = f()
if not !found && x = y
then found := true; loop()
else y
loop
let cons x f =
let first = ref true
fun () ->
if !first
then first := false; x
else f()
let next =
let i = ref 0
fun () -> incr i; !i
Seq.unfold (fun next ->
let r = next()
let s = next()
Some(r, (cons (r+s) (delete (r+s) next)))) next
答案 2 :(得分:3)
实际上,你可以使用过滤器和跟随haskell解决方案的设计(但是,正如@pad所说,你没有序列上的模式匹配;所以我使用了lisp风格的破坏):
let infinite = Seq.initInfinite (fun i -> i+1)
let generator = fun ss -> let (r, st) = (Seq.head ss, Seq.skip 1 ss)
let (s, stt) = (Seq.head st, Seq.skip 1 st)
let srps = seq [ r + s ]
let filtered = Seq.filter (fun t -> (r + s) <> t) stt
Some (r, Seq.append srps filtered)
let hofstadter = Seq.unfold generator infinite
let t10 = Seq.take 10 hofstadter |> Seq.toList
// val t10 : int list = [1; 3; 7; 12; 18; 26; 35; 45; 56; 69]
我对效率没有任何要求!