F# Bjorklund 算法:将 while 循环转换为递归函数:类型约束问题
F# Bjorklund algorithm: convert while-loop to recursive function: type-constraint issue
我终于深入研究了 f#。长期使用 c 风格命令式的人 - 但所有语言的爱好者。我正在尝试欧几里德节奏的 Bjorklund 算法。 Bjorklund:二进制字符串中 1 的最相等间距直到旋转,例如1111100000000 -> 1001010010100。
https://erikdemaine.org/papers/DeepRhythms_CGTA/paper.pdf
我最初的尝试基于一个不错的 js/lodash 实现。我从头开始尝试,但都被旧概念束缚了。
https://codepen.io/teropa/details/zPEYbY
这是我的 1:1 翻译
let mutable pat = "1111100000000" // more 0 than 1
//let mutable pat = "1111111100000" // more 1 than 0
//
let compareSequences = Seq.compareWith Operators.compare
let mutable apat = Array.map (fun a -> [a]) ( Seq.toArray pat )
let mutable cond = true
while cond do
let (head, rem) = Array.partition (fun v -> (compareSequences v apat.[0]) = 0) apat
cond <- rem.Length > 1
match cond with
| false -> ()
| true ->
for i=0 to (min head.Length rem.Length)-1 do
apat.[i] <-apat.[i] @ apat.[^0]
apat <- apat.[.. ^1]
let tostring (ac : char list) = (System.String.Concat(Array.ofList(ac)))
let oned = (Array.map (fun a -> tostring a) apat )
let res = Array.reduce (fun a b -> a+b) oned
printfn "%A" res
这似乎行得通。但是因为我想(学习)发挥作用,而不是 necc。尽可能惯用,我想失去 while 并递归主要算法。
现在我有了这个:
let apat = Array.map (fun a -> [a]) ( Seq.toArray pat )
let rec bjork bpat:list<char> array =
let (head, rem) = Array.partition (fun v -> (compareSequences v bpat.[0]) = 0) bpat
match rem.Length > 1 with
| false -> bpat
| true ->
for i=0 to (min head.Length rem.Length)-1 do
bpat.[i] <-bpat.[i] @ bpat.[^0]
bjork bpat.[.. ^1]
let ppat = bjork apat
问题是 compareSequences 的第二个参数:bpat。[0]我收到错误:
运算符 'expr.[idx]' 已根据此程序点之前的信息用于不确定类型的对象。考虑添加更多类型约束
我有点困惑,因为这看起来与 while 循环版本非常相似。我可以看到 compareSequences 的签名不同但不知道为什么。除了可变性之外,apat 在每个版本中都具有相同的类型。第二版中的 bpat 与 apat 类型相同。
while 循环:char list -> char list -> int
记录功能:char list -> seq<char> -> int
我会说我在学习 f# 时遇到了一些奇怪的错误,这些错误最终与代码中其他地方的问题有关,所以希望这不是百灵鸟。
此外,可能还有其他方法可以做到这一点,包括 Bresenham 的线算法,但我正在学习轨道上,这似乎是几个功能概念的好算法。
谁能看到我在这里遗漏了什么?此外,如果精通 functional/f# 范式的人有解决此问题的好方法,我希望看到。
谢谢
泰德
编辑:
上面的递归不起作用。只是无法测试。这有效,但仍然有一个可变的。
let rec bjork (bbpat:list<char> array) =
let mutable bpat = bbpat
let (head, rem) = Array.partition (fun v -> (compareSequences v bpat.[0]) = 0) bpat
match rem.Length > 1 with
| false -> bpat
| true ->
for i=0 to (min head.Length rem.Length)-1 do
bpat.[i] <-bpat.[i] @ bpat.[^0]
bpat <- bpat.[.. ^1]
bjork bpat
您需要在 (bpat:list<char> array)
两边加上括号。否则类型注释适用于 bjork
,不适用于 bbpat
:
let rec bjork (bbpat:list<char> array) =
...
另请注意,计算长度和索引都是 F# 链表上的 O(n) 操作。考虑改为模式匹配。
我终于深入研究了 f#。长期使用 c 风格命令式的人 - 但所有语言的爱好者。我正在尝试欧几里德节奏的 Bjorklund 算法。 Bjorklund:二进制字符串中 1 的最相等间距直到旋转,例如1111100000000 -> 1001010010100。
https://erikdemaine.org/papers/DeepRhythms_CGTA/paper.pdf
我最初的尝试基于一个不错的 js/lodash 实现。我从头开始尝试,但都被旧概念束缚了。
https://codepen.io/teropa/details/zPEYbY
这是我的 1:1 翻译
let mutable pat = "1111100000000" // more 0 than 1
//let mutable pat = "1111111100000" // more 1 than 0
//
let compareSequences = Seq.compareWith Operators.compare
let mutable apat = Array.map (fun a -> [a]) ( Seq.toArray pat )
let mutable cond = true
while cond do
let (head, rem) = Array.partition (fun v -> (compareSequences v apat.[0]) = 0) apat
cond <- rem.Length > 1
match cond with
| false -> ()
| true ->
for i=0 to (min head.Length rem.Length)-1 do
apat.[i] <-apat.[i] @ apat.[^0]
apat <- apat.[.. ^1]
let tostring (ac : char list) = (System.String.Concat(Array.ofList(ac)))
let oned = (Array.map (fun a -> tostring a) apat )
let res = Array.reduce (fun a b -> a+b) oned
printfn "%A" res
这似乎行得通。但是因为我想(学习)发挥作用,而不是 necc。尽可能惯用,我想失去 while 并递归主要算法。
现在我有了这个:
let apat = Array.map (fun a -> [a]) ( Seq.toArray pat )
let rec bjork bpat:list<char> array =
let (head, rem) = Array.partition (fun v -> (compareSequences v bpat.[0]) = 0) bpat
match rem.Length > 1 with
| false -> bpat
| true ->
for i=0 to (min head.Length rem.Length)-1 do
bpat.[i] <-bpat.[i] @ bpat.[^0]
bjork bpat.[.. ^1]
let ppat = bjork apat
问题是 compareSequences 的第二个参数:bpat。[0]我收到错误:
运算符 'expr.[idx]' 已根据此程序点之前的信息用于不确定类型的对象。考虑添加更多类型约束
我有点困惑,因为这看起来与 while 循环版本非常相似。我可以看到 compareSequences 的签名不同但不知道为什么。除了可变性之外,apat 在每个版本中都具有相同的类型。第二版中的 bpat 与 apat 类型相同。
while 循环:char list -> char list -> int
记录功能:char list -> seq<char> -> int
我会说我在学习 f# 时遇到了一些奇怪的错误,这些错误最终与代码中其他地方的问题有关,所以希望这不是百灵鸟。
此外,可能还有其他方法可以做到这一点,包括 Bresenham 的线算法,但我正在学习轨道上,这似乎是几个功能概念的好算法。
谁能看到我在这里遗漏了什么?此外,如果精通 functional/f# 范式的人有解决此问题的好方法,我希望看到。
谢谢 泰德
编辑:
上面的递归不起作用。只是无法测试。这有效,但仍然有一个可变的。
let rec bjork (bbpat:list<char> array) =
let mutable bpat = bbpat
let (head, rem) = Array.partition (fun v -> (compareSequences v bpat.[0]) = 0) bpat
match rem.Length > 1 with
| false -> bpat
| true ->
for i=0 to (min head.Length rem.Length)-1 do
bpat.[i] <-bpat.[i] @ bpat.[^0]
bpat <- bpat.[.. ^1]
bjork bpat
您需要在 (bpat:list<char> array)
两边加上括号。否则类型注释适用于 bjork
,不适用于 bbpat
:
let rec bjork (bbpat:list<char> array) =
...
另请注意,计算长度和索引都是 F# 链表上的 O(n) 操作。考虑改为模式匹配。