7

私は現在、DICOM を扱う必要がある次のプロジェクトで Scala を使用するつもりで、Scala に取り組もうとしています。DICOM には、標準の何千ページにもわたる非常に幅広い仕様があります。DICOM についての私の理解はかなり限られていますが、要するに DICOM オブジェクト - IOD (情報オブジェクト定義) はモジュールで構成されており、モジュールは型指定された名前と値の属性ペアのコレクションです。一部のモジュールと属性のオプション性により、さらに複雑になります。例えば:

SimpleImageIOD: {
    PatientModule: {
        name: String
        dateOfBirth: DateTime
    }
    StudyModule: {
        name: String
        date: DateTime (optional)
    }
    SeriesModule: {
        name: String
    }
    ImageModule: {
        height: Integer
        width: Integer
        pixelSize: Double (optional)
    }
    EquipmentModule: { (optional)
        type: String
    }
}

たくさんのモジュールがあり、さまざまな IOD を形成するさまざまな組み合わせで構成されている可能性があります。同様に、Scala には、すべてのトレイト、ケース クラス、動的クラスなどを備えた多くのモデリング機能があります。そのようなドメインを Scala でどのようにモデル化しますか? 私はこの言語にまったく慣れていませんが、不変のケース クラスを使用してモジュールを定義し、それらをさまざまな IOD に集約し、レンズを使用して更新することを考えていました。

case class Patient(name: String, dateOfBirth: DateTime)
case class Study(name: String, date: Option[DateTime])
case class Series(name: String)
case class Image(height: Integer, width: Integer, pixelSize: Option[Double])
case class Equipment(type: String)

case class SimpleImageIOD(patient: Patient, study: Study, series: Series, 
                          image: Image, equipment: Option[Equipment])

object Patient {
    val nameL: Lens[Patient, String] = ...
    val dateOfBirthL: Lens[Patient, DateTime] = ...
}

object SimpleImageIOD {
    val patientL: Lens[SimpleImageIOD, Patient] = ...
    val patientNamel = patientL andThen Patient.nameL
}

などなど。レンズに関しては、すべてのボイラープレートをコーディングすることが問題になる可能性があります。IOD、モジュール、および属性M x N x Lのドメイン全体をカバーするレンズの順序があります。また、一部のフィールドのオプション性により、少なくとも ではタスクが非常に複雑になります。MNLscalaz-seven

Scala の精神に沿った実行可能なアプローチは他にあるでしょうか?

4

1 に答える 1

5

M x N x Lレンズを入れ子にすることができるので、全部でレンズを持っているとは思いません。それは完全に合理的なアプローチだと思います。

別のアプローチは、次のように独自の単一エントリ更新メソッドを定義することです。

case class Patient(name: String, dateOfBirth: Long) {
  def name(f: String => String): Patient = copy(name = f(name))
  def dateOfBirth(f: Long => Long): Patient = copy(dateOfBirth = f(dateOfBirth))
}

あなたはそのように使用します:

scala> Patient("John",0).name(_ + " Smith")
res1: Patient = Patient(John Smith,0)

これはレンズである程度達成可能ですが、(使用法と定義の両方で)大幅に多くの定型文を使用しないように十分に注意する必要があります。機能(更新など)を任意に引き離すことができるレンズの柔軟性はありませんが、合理化することでそれを補います。

私はこの方法で私の深い更新の大部分を行います:

myImage.patient(_.study(_.date(_ => Some(System.currentTimeMillis))))

現在の時刻のスタディでツリー全体を更新する必要があるのはこれだけです(ここでDateTimeは実際にはのふりをしますLong)。この特定のツリーを再生するこの機能を実際に抽出する必要がある場合(レンズを使用するとより自然になります)、あなたは出来る

val setStudyTime = (t: Long) => myImage.patient(_.study(_.date(_ => Some(t))))

あるいは

def studyTimeSetter(si: SimpleImageIOD) =
  (t: Long) => si.patient(_.study(_.date(_ => Some(t))))

この機能をすぐに入手する必要がある場合。

レンズが提供するすべてのものが必要な場合は、このアプローチを使用してアドホックな方法でレンズを再構築する必要がありますが、必要なのはごく一部で、ほとんどの場合、設定のためにボイラープレートを削減する必要がある場合、これはかなり良いことです仕事。

于 2013-03-23T20:34:38.850 に答える