2016-07-14 7 views
0

私は2つのデータ構造itemDtoとitemEntityを持っています。将来のScalaz機能構成

trait ItemDto{ 
    def id: Long 
    def name: String 
} 

trait ItemEntity { 
    def id: Long 
    def name: String 
} 

case class Entity(id: Long, name: String) extends ItemEntity 

case class Dto(id: Long, name: String) extends ItemDto 

私はいくつかのマッパー機能だけでなく

object ItemMapper { 

    def mapDtoToEntity(dto: ItemDto): ItemEntity = { 
    Entity(dto.id, dto.name) 
    } 

    def mapEntityToDto(entity: ItemEntity): ItemDto = { 
    Dto(entity.id, entity.name) 
    } 
} 

エンティティのIDをインクリメント機能を持っている

ItemDto => ItemEntity => ItemEntity => Future[ItemEntity] => Future[ItemEntity] => Future[ItemDto] 

次のようになり、パイプラインを設定したいと思い

object ItemEntity{ 
    def incrementId(entity: ItemEntity) = Entity(entity.id + 1, entity.name) 
} 

とSaveメソッドがチェーンで呼び出された後

object ItemRepository { 

    def save(entity: ItemEntity): Future[ItemEntity] = { 
     Future{entity} 
    } 
} 

エンティティを保存するためのリポジトリが最終的に何かをするために、これらすべての機能を組み合わせた、私の方法は、この

import ItemMapper._ 
import ItemRepository.save 
import ItemEntity.incrementId 

def addItem(dto: ItemDto) = { 
    (mapDtoToEntity _ >>> incrementId >>> save >>> {_ map (incrementId _ >>> mapEntityToDto) })(dto) 
} 

のように見えている再、私は破るために持っています別の機能に変換する。私の質問は、将来の価値を持ち上げて戻す方法ですか?私のパイプラインはこういう風に見えますか?

(mapDtoToEntity _ >>> incrementId >>> save ?!? incrementId ?!? mapEntityToDto)(dto) 

ここで、?!?は仮説的演算子である。

これはスカラーライブラリからのものでもあります。それはscalazからである必要はありません。

答えて

1

F[_](ここではFutureのような)を返す関数を作成するためにscalaz(またはcats)から最も有用な概念はKeisliの矢印です。

Kleisliは、複数のA => F[B]関数を簡単に作成できます。ここでは実際にはItemEntity => Future[ItemEntity]という機能しかありません。

我々は最初の3つの機能からKleisli[Future, ItemDto, ItemEntity]を作成してから、最後の二つを使用してその上にマッピングすることができます。

import scalaz._, Scalaz._ 
import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

val composition1: Kleisli[Future, ItemDto, ItemDto] = 
    Kleisli(mapDtoToEntity _ >>> incrementId >>> save) 
    .map(incrementId _ >>> mapEntityToDto) 

あなたがしたい、実際の操作は、残りはDtoからEntityへの変換で、saveですidをインクリメントしながら(2回)戻る。

我々はKleisli(save)dimap(私たちはProfunctorから取得する操作)を呼び出すことにより、saveの前と後の変換と増分を行うことができます。

val composition2: Kleisli[Future, ItemDto, ItemDto] = 
    Kleisli(save).dimap(
    mapDtoToEntity _ >>> incrementId, 
    incrementId _ >>> mapEntityToDto) 

か二度dimapを使用して:

val composition3: Kleisli[Future, ItemDto, ItemDto] = 
    Kleisli(save).dimap(incrementId, incrementId) 
       .dimap(mapDtoToEntity, mapEntityToDto) 

どちらも同じ結果をもたらす:

猫では210

これは多かれ少なかれ同じになります。

  • 猫を(現在は)>>>演算子を持っていないので、andThenで交換する必要があります。
  • dimapが書き込まれているので、dimap(f, g)の代わりにdimap(f)(g)と書きます。
+0

kleisliの本当に良い説明をありがとう。私はそれに幾分慣れていましたが、今はもっとよく理解しています。私は本当にこれを自動的に行い、そこにあるように見えない演算子があったかどうか疑問に思っていました。 btwでは、パイプライン内の複数の操作の重複した例が考案されました。私は自分のプロジェクトでそれをやっていません。 – decapo