序列表达式和多态递归如何一起发挥作用?
How do sequence expressions and polymorphic recursion play together?
This project really is a questions 对我来说。
我已经了解了多态递归并且我明白为什么它是一种特殊情况,因此 F# 需要完整的类型注释。
对于常规函数,我可能需要一些操作,但通常都能正确完成。现在,我正在尝试将(工作中的)基本 toSeq
改编为更专业的手指树,但做不到。
我的感觉是计算表达式的使用有点关系。这是精简版:
module ThisWorks =
module Node =
type Node<'a> =
| Node2 of 'a * 'a
| Node3 of 'a * 'a * 'a
let toList = function
| Node2(a, b) -> [a; b]
| Node3(a, b, c) -> [a; b; c]
module Digit =
type Digit<'a> =
| One of 'a
| Two of 'a * 'a
| Three of 'a * 'a * 'a
| Four of 'a * 'a * 'a * 'a
let toList = function
| One a -> [a]
| Two(a, b) -> [a; b]
| Three(a, b, c) -> [a; b; c]
| Four(a, b, c, d) -> [a; b; c; d]
module FingerTree =
open Node
open Digit
type FingerTree<'a> =
| Empty
| Single of 'a
| Deep of Digit<'a> * Lazy<FingerTree<Node<'a>>> * Digit<'a>
let rec toSeq<'a> (tree:FingerTree<'a>) : seq<'a> = seq {
match tree with
| Single single ->
yield single
| Deep(prefix, Lazy deeper, suffix) ->
yield! prefix |> Digit.toList
yield! deeper |> toSeq |> Seq.collect Node.toList
yield! suffix |> Digit.toList
| Empty -> ()
}
我没能编译的是这个:
module ThisDoesnt =
module Monoids =
type IMonoid<'m> =
abstract Zero:'m
abstract Plus:'m -> 'm
type IMeasured<'m when 'm :> IMonoid<'m>> =
abstract Measure:'m
type Size(value) =
new() = Size 0
member __.Value = value
interface IMonoid<Size> with
member __.Zero = Size()
member __.Plus rhs = Size(value + rhs.Value)
type Value<'a> =
| Value of 'a
interface IMeasured<Size> with
member __.Measure = Size 1
open Monoids
module Node =
type Node<'m, 'a when 'm :> IMonoid<'m>> =
| Node2 of 'm * 'a * 'a
| Node3 of 'm * 'a * 'a * 'a
let toList = function
| Node2(_, a, b) -> [a; b]
| Node3(_, a, b, c) -> [a; b; c]
module Digit =
type Digit<'m, 'a when 'm :> IMonoid<'m>> =
| One of 'a
| Two of 'a * 'a
| Three of 'a * 'a * 'a
| Four of 'a * 'a * 'a * 'a
let toList = function
| One a -> [a]
| Two(a, b) -> [a; b]
| Three(a, b, c) -> [a; b; c]
| Four(a, b, c, d) -> [a; b; c; d]
module FingerTree =
open Node
open Digit
type FingerTree<'m, 'a when 'm :> IMonoid<'m>> =
| Empty
| Single of 'a
| Deep of 'm * Digit<'m, 'a> * Lazy<FingerTree<'m, Node<'m, 'a>>> * Digit<'m, 'a>
let unpack (Value v) = v
let rec toSeq<'a> (tree:FingerTree<Size, Value<'a>>) : seq<'a> = seq {
match tree with
| Single(Value single) ->
yield single
| Deep(_, prefix, Lazy deeper, suffix) ->
yield! prefix |> Digit.toList |> List.map unpack
#if ITERATE
for (Value deep) in toSeq deeper do
^^^^^
yield deep
#else
yield! deeper |> toSeq |> Seq.collect (Node.toList >> List.map unpack)
^^^^^
#endif
yield! suffix |> Digit.toList |> List.map unpack
| Empty -> ()
}
我收到的错误消息说
Error Type mismatch. Expecting a
FingerTree<Size,Node<Size,Value<'a>>> -> 'b
but given a
FingerTree<Size,Value<'c>> -> seq<'c>
The type 'Node<Size,Value<'a>>' does not match the type 'Value<'b>'
并且波浪线强调了 toSeq
的递归调用。
我知道“更深层次的”类型封装在 Node
中,在工作代码中我只是在之后解压它。但是在这里,编译器在我有机会解包之前就已经出错了。尝试 for (Value deep) in toSeq deeper do yield deep
有同样的问题。
我已经有办法了,就是用“基”的toSeq
Tree
,然后Seq.map unpack
。不是是的,尝试会产生非常相似的错误消息。
我很好奇是什么导致此代码损坏以及如何修复它。
编译器的错误消息对我来说似乎很清楚:toSeq
is applicable only to values of type FingerTree<Size, Value<'a>>
for some 'a
,但你试图在一个值上调用它相反,类型 FingerTree<Size,Node<Size,Value<'a>>>
是不兼容的。没有什么特定于多态递归或序列表达式,这些类型只是不匹配。
相反,通过采用 FingerTree<Size, 'a>
类型的输入(不引用 Value
)使 toSeq
更通用似乎会简单得多,这将使你想要的递归调用。然后,您可以通过将更通用的 toSeq
与 Seq.map unpack
.
组合起来,轻松导出您实际想要的更具体的功能
This project really is a
我已经了解了多态递归并且我明白为什么它是一种特殊情况,因此 F# 需要完整的类型注释。
对于常规函数,我可能需要一些操作,但通常都能正确完成。现在,我正在尝试将(工作中的)基本 toSeq
改编为更专业的手指树,但做不到。
我的感觉是计算表达式的使用有点关系。这是精简版:
module ThisWorks =
module Node =
type Node<'a> =
| Node2 of 'a * 'a
| Node3 of 'a * 'a * 'a
let toList = function
| Node2(a, b) -> [a; b]
| Node3(a, b, c) -> [a; b; c]
module Digit =
type Digit<'a> =
| One of 'a
| Two of 'a * 'a
| Three of 'a * 'a * 'a
| Four of 'a * 'a * 'a * 'a
let toList = function
| One a -> [a]
| Two(a, b) -> [a; b]
| Three(a, b, c) -> [a; b; c]
| Four(a, b, c, d) -> [a; b; c; d]
module FingerTree =
open Node
open Digit
type FingerTree<'a> =
| Empty
| Single of 'a
| Deep of Digit<'a> * Lazy<FingerTree<Node<'a>>> * Digit<'a>
let rec toSeq<'a> (tree:FingerTree<'a>) : seq<'a> = seq {
match tree with
| Single single ->
yield single
| Deep(prefix, Lazy deeper, suffix) ->
yield! prefix |> Digit.toList
yield! deeper |> toSeq |> Seq.collect Node.toList
yield! suffix |> Digit.toList
| Empty -> ()
}
我没能编译的是这个:
module ThisDoesnt =
module Monoids =
type IMonoid<'m> =
abstract Zero:'m
abstract Plus:'m -> 'm
type IMeasured<'m when 'm :> IMonoid<'m>> =
abstract Measure:'m
type Size(value) =
new() = Size 0
member __.Value = value
interface IMonoid<Size> with
member __.Zero = Size()
member __.Plus rhs = Size(value + rhs.Value)
type Value<'a> =
| Value of 'a
interface IMeasured<Size> with
member __.Measure = Size 1
open Monoids
module Node =
type Node<'m, 'a when 'm :> IMonoid<'m>> =
| Node2 of 'm * 'a * 'a
| Node3 of 'm * 'a * 'a * 'a
let toList = function
| Node2(_, a, b) -> [a; b]
| Node3(_, a, b, c) -> [a; b; c]
module Digit =
type Digit<'m, 'a when 'm :> IMonoid<'m>> =
| One of 'a
| Two of 'a * 'a
| Three of 'a * 'a * 'a
| Four of 'a * 'a * 'a * 'a
let toList = function
| One a -> [a]
| Two(a, b) -> [a; b]
| Three(a, b, c) -> [a; b; c]
| Four(a, b, c, d) -> [a; b; c; d]
module FingerTree =
open Node
open Digit
type FingerTree<'m, 'a when 'm :> IMonoid<'m>> =
| Empty
| Single of 'a
| Deep of 'm * Digit<'m, 'a> * Lazy<FingerTree<'m, Node<'m, 'a>>> * Digit<'m, 'a>
let unpack (Value v) = v
let rec toSeq<'a> (tree:FingerTree<Size, Value<'a>>) : seq<'a> = seq {
match tree with
| Single(Value single) ->
yield single
| Deep(_, prefix, Lazy deeper, suffix) ->
yield! prefix |> Digit.toList |> List.map unpack
#if ITERATE
for (Value deep) in toSeq deeper do
^^^^^
yield deep
#else
yield! deeper |> toSeq |> Seq.collect (Node.toList >> List.map unpack)
^^^^^
#endif
yield! suffix |> Digit.toList |> List.map unpack
| Empty -> ()
}
我收到的错误消息说
Error Type mismatch. Expecting a
FingerTree<Size,Node<Size,Value<'a>>> -> 'b
but given a
FingerTree<Size,Value<'c>> -> seq<'c>
The type 'Node<Size,Value<'a>>' does not match the type 'Value<'b>'
并且波浪线强调了 toSeq
的递归调用。
我知道“更深层次的”类型封装在 Node
中,在工作代码中我只是在之后解压它。但是在这里,编译器在我有机会解包之前就已经出错了。尝试 for (Value deep) in toSeq deeper do yield deep
有同样的问题。
我已经有办法了,就是用“基”的不是是的,尝试会产生非常相似的错误消息。toSeq
Tree
,然后Seq.map unpack
。
我很好奇是什么导致此代码损坏以及如何修复它。
编译器的错误消息对我来说似乎很清楚:toSeq
is applicable only to values of type FingerTree<Size, Value<'a>>
for some 'a
,但你试图在一个值上调用它相反,类型 FingerTree<Size,Node<Size,Value<'a>>>
是不兼容的。没有什么特定于多态递归或序列表达式,这些类型只是不匹配。
相反,通过采用 FingerTree<Size, 'a>
类型的输入(不引用 Value
)使 toSeq
更通用似乎会简单得多,这将使你想要的递归调用。然后,您可以通过将更通用的 toSeq
与 Seq.map unpack
.