1

This project은 실제로 나를 위해 sourceofquestions입니다.시퀀스 식과 다형성 재귀가 함께 어떻게 작동합니까?

나는 다형성 재귀에 대해 이미 배웠고 특별한 경우 인 이유를 이해하고 있으며 따라서 F #에는 전체 형식 주석이 필요합니다.

정규 기능의 경우 약간의 경매가 필요할 수 있지만 일반적으로 올바르게 처리됩니다. 이제는 (작동하는) 기본 toSeq을보다 특수화 된 손가락 트리에 적용하려고하지만 할 수 없습니다.

제 생각에 계산 표현식을 사용하는 것과 관련이 있습니다.

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

내가 오류 메시지가

오류 유형 불일치를 말한다 :

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

내가 컴파일 얻을 관리하지 않는 한이 있습니다 :이 응축 된 작동 버전입니다 .
b를하지만
FingerTree < 크기, 값 < '> > C - 서열 < >'주어 - '> > > >'는
FingerTree < 크기, 노드 < 크기, 값 <을 기대 C를 >
형식 '노드 < 크기, 값 <'a > > '이'값 < '형식과 일치하지 않습니다. >'

그리고 squiggles는 toSeq의 재귀 호출에 밑줄을 긋습니다.

"더 깊은"유형이 Node에 캡슐화되어 있으며 작업 코드에서 나중에 압축을 풀었습니다. 하지만 여기서 컴파일러는 이미 압축을 풀기 전에 이동합니다. for (Value deep) in toSeq deeper do yield deep을 시도하면 같은 문제가 발생합니다.

는 이미 즉 "기본"이후 TreeSeq.map unpacktoSeq를 사용하여, 밖으로 방법이있다. 사실이 아니라면 비슷한 오류 메시지가 나타납니다.

나는이 코드를 어떻게 만들지, 어떻게 고칠 수 있는지 궁금합니다. toSeq는 일부 'a에 대한 유형 FingerTree<Size, Value<'a>>의 값을 적용 할 수 있지만 호환되지 않는 대신 유형 FingerTree<Size,Node<Size,Value<'a>>>의 값에 호출하려는 :

답변

3

컴파일러의 오류 메시지가 나에게 분명한 것 같다. 다형성 재귀 또는 시퀀스 식에만 해당하는 것은 없습니다. 이러한 유형은 일치하지 않습니다. 당신이 원하는 재귀 호출을 가능하게 것이다, (Value에 대한 참조없이) 형 FingerTree<Size, 'a>의 입력을 취함으로써 toSeq 더 일반적인 만들 훨씬 간단 할 것 같은

는 대신 보인다.그런 다음 좀더 일반적인 toSeqSeq.map unpack으로 작성하여 실제로 원하는 특정 기능을 쉽게 파생시킬 수 있습니다.