2017-08-26 10 views
2

私はFree Monads of Catsで遊んでいます。私はCSVレコードを処理するためにDSLを書いています。基本的な操作はCSVレコードを処理することであり、私はprocessCSVRecordsの操作のためにヘルパーsequencemap2の関数を書いています。私はケースクラスの戻り値の型をジェネリック型Rにします。以下は私が使用しているコードです。私は上記のコードをコンパイルしようとすると、なぜFree Monad InterpreterはString to Id [A]を解決しないのですか

import cats.data.Coproduct 
import cats.free.Free.inject 
import cats.free.{Free, Inject} 
import cats.{Id, ~>} 
import org.apache.commons.csv.CSVRecord 

object ProcessCSVActions { 

    sealed trait ProcessCSV[A] 

    case class ProcessCSVRecord[R](csvRecord: CSVRecord) extends ProcessCSV[R] 

    class ProcessCSVs[F[_]](implicit I: Inject[ProcessCSV, F]) { 

    private def sequence[S[_], A](fs: Stream[Free[S, A]]): Free[S, Stream[A]] = 
     fs.reverse.foldLeft[Free[S, Stream[A]]](Free.pure[S, Stream[A]](Stream()))((b, a) => map2(a, b)(_ #:: _)) 

    private def map2[S[_], A, B, C](ra: Free[S, A], rb: Free[S, B])(f: (A, B) => C): Free[S, C] = for { 
     a <- ra 
     b <- rb 
    } yield f(a, b) 

    def processCSVRecord[R](csvRecord: CSVRecord): Free[F, R] = 
     inject[ProcessCSV, F](ProcessCSVRecord[R](csvRecord)) 

    def processCSVRecords[R](csvRecords: Stream[CSVRecord]): Free[F, Stream[R]] = { 
     val res: Stream[Free[F, R]] = for { 
     csvRecord <- csvRecords 
     } yield processCSVRecord[R](csvRecord) 
     sequence[F, R](res) 
    } 


    } 

    object ProcessCSVs { 
    def apply[F[_]](implicit I: Inject[ProcessCSV, F]): ProcessCSVs[F] = new ProcessCSVs[F] 
    } 

    object StringInterpreterOfCSV extends (ProcessCSV ~> Id) { 
    override def apply[A](fa: ProcessCSV[A]): Id[A] = fa match { 
     case ProcessCSVRecord(csvRecord) => csvRecord.get(2) 
    } 
    } 
} 

は今、私は私の通訳のために、以下のエラーが表示されます。

[scalac-2.11] found : String 
[scalac-2.11] required: cats.Id[A] 
[scalac-2.11]  (which expands to) A 
[scalac-2.11]  case ProcessCSVRecord(csvRecord) => csvRecord.get(2) 
[scalac-2.11]              ^
[scalac-2.11] one error found 

FreeStreamを処理するための適切な方法は何ですか?

編集:

私はハックを発見しました。ケースクラスにはRというタイプのパラメータを取っています。

case class ProcessCSVRecord[R](csvRecord: CSVRecord, a:Option[R]) extends ProcessCSV[R] 
    def processCSVRecord[R](csvRecord: CSVRecord): Free[F, R] = 
     inject[ProcessCSV, F](ProcessCSVRecord[R](csvRecord, None)) 

インタープリタでは、結果に一致するタイプを明示的に指定しています。

object StringInterpreterOfCSV extends (ProcessCSV ~> Id) { 
    override def apply[A](fa: ProcessCSV[A]): Id[A] = fa match { 
     case ProcessCSVRecord(csvRecord, _: Option[String]) => csvRecord.get(2) 
    } 
    } 

上記の作業はありましたが、私はこのハックの代わりにより良い解決策があることを望みました。

+0

あなたは実際にケースクラスに 'R'を使用していますか?あなたの例では冗長であるように見えるからです。 –

+0

はい。私は自分のプログラムでそれを使っています(理解のために)。私はCSV解析スクリプトを書いており、通常パターンは同じです。だから、私は自分のケースクラスを再利用し、スクリプトのためにプログラムとインタプリタだけを書こうと思っていました。 – arjunswaj

答えて

2

CSVRecordAとは関係がないため、コンパイラにはString <:< Aというエビデンスはありません。これをコンパイルすると、ProcessCSV[Int]を作成してStringInterpreterOfCSV.applyに渡すことができますが、それは意味をなさないことです。

CSVRecord typeパラメータRを持っていた、とget(2)Rを返した場合、それは動作します:

case class ProcessCSVRecord[R](csvRecord: CSVRecord[R]) extends ProcessCSV[R] 

そうでなければ、することができますcsvRecord.get(2).asInstanceOf[A]

関連する問題