1

这个项目对我来说确实是一个问题的来源

我已经了解了多态递归,并且理解为什么它是一种特殊情况,因此 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 -> ()
        }

我收到的错误消息说

错误类型不匹配。期望
FingerTree<Size,Node<Size,Value<'a>>> -> 'b
但给定了
FingerTree<Size,Value<'c>> -> seq<'c>
类型 'Node<Size,Value< 'a>>' 与类型 'Value<'b>' 不匹配

曲线下划线的递归调用toSeq

我知道“更深”的类型被封装在 aNode中,并且在工作代码中我​​只是在之后解压缩它。但是在我有机会解包之前,编译器已经跳闸了。尝试 afor (Value deep) in toSeq deeper do yield deep有同样的问题。

我已经有一个出路,即使用toSeq“基地”TreeSeq.map unpack之后。不正确,尝试会产生非常相似的错误消息。

我很好奇是什么让这段代码中断以及如何修复它。

4

1 回答 1

3

编译器的错误消息对我来说似乎很清楚:toSeq仅适用FingerTree<Size, Value<'a>>于 some类型的值'a,但您试图在FingerTree<Size,Node<Size,Value<'a>>>不兼容的类型值上调用它。没有什么特定于多态递归或序列表达式,这些类型只是不匹配。

toSeq相反,通过输入类型FingerTree<Size, 'a>(没有任何引用)来使更通用化似乎要简单得多Value,这将启用您想要的递归调用。toSeq然后,您可以通过将更通用的与组合起来,轻松推导出您真正想要的更具体的功能Seq.map unpack

于 2016-11-14T16:48:35.667 回答