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 ->() 
     } 

私はコンパイルするために取得するために管理していない1本です:

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 ->() 
     } 

私が取得エラーメッセージが

エラータイプの不一致を語ります。 B
しかし '> > C - >配列<'
2-3フィンガーツリー<サイズ、値<を所与 -
2-3フィンガーツリー<サイズ、ノード<サイズ、値< '> > > >' を期待>
C型 'ノード<サイズ、値<' > > 'がタイプ'値< 'と一致しません。>'

そして、スクイブルは、toSeqの再帰呼び出しに下線を引いている。

「より深い」タイプはNodeにカプセル化されており、作業コードでは後で解凍するだけです。しかし、ここでコンパイラは、私が解凍するチャンスを得る前に既に移動しています。 for (Value deep) in toSeq deeper do yield deepを試しても同じ問題があります。

は、私はすでに、「ベース」その後TreeSeq.map unpacktoSeqを使用すること、すなわち、アウトの方法を持っています。本当ではない、試してみると、非常に似たエラーメッセージが表示されます。

私はこのコードブレークをどのようにして修正できるのか不思議です。

答えて

3

コンパイラのエラーメッセージが私には明確なようだ:toSeqは一部だけ'a用タイプFingerTree<Size, Value<'a>>の値に適用されていますが、互換性がありません。これは、代わりにタイプFingerTree<Size,Node<Size,Value<'a>>>の値でそれを呼び出すようにしようとしています。多態的な再帰やシーケンス式に特有のものは何もありません。これらの型は単に一致しません。

Valueへの参照なし)タイプFingerTree<Size, 'a>の入力を取ることによってtoSeqは、より汎用的にするために非常に簡単になるようにする代わりに、あなたが望む再帰呼び出しを可能にすることになる、と思われます。次に、一般的なtoSeqSeq.map unpackとすることで、より具体的な機能を簡単に導き出すことができます。

関連する問題