1

This project对我来说真的是sourceofquestions序列表达式和多态递归如何一起玩?

我已经了解了多态递归,我明白为什么它是一个特殊情况,因此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 <大小,节点<尺寸,价值< '一个> > > - >' B
但给予
FingerTree <尺寸,价值< 'C > > - >序列<' C >
的类型'节点<大小,值<'a > >'与类型'值不匹配'值<'b >'

并且波浪线强调递归调用toSeq

我知道“更深”的类型封装在Node和工作代码中,我之后只是将其解压缩。但是在这里,编译器在我有机会解包之前就已经出发了。尝试for (Value deep) in toSeq deeper do yield deep也有同样的问题。

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

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

回答

3

编译器的错误信息似乎很清楚对我说:toSeq仅适用于某些'aFingerTree<Size, Value<'a>>类型的值,但是你要调用它FingerTree<Size,Node<Size,Value<'a>>>型而不是价值,这是不兼容的。没有什么特别的多态递归或序列表达式,这些类型只是不匹配。

相反,它似乎将变得更简单,使toSeq更通用采取FingerTree<Size, 'a>类型的输入(没有任何参考Value),这将使你想要的递归调用。然后,通过编写更一般的toSeqSeq.map unpack,您可以轻松推导出您实际需要的更具体的功能。