2017-02-17 2 views
2

私はF#を初めて使用しています。いくつかのタイプを設計しようとすると、OOPが設計上の意思決定にどれだけ影響を与えたのか気づきました。私はこの特定の問題を探すのに苦労し、空手になった。インターフェイスからの隠された基礎となる実装でF#タイプを設計

私はC#で何をしようとしているのか、私は用語に詳しいことがあるので説明します。私は、コンテナのようなクラスに最低限必要ないくつかのメソッドを指定するインタフェースを持っているとしましょう。それを​​としましょう。次に、私はこのインターフェイスを実装する2つのクラス、ContainerAContainerBを、ユーザーから隠されているさまざまな基本的な実装を持っています。これは非常に一般的なOOPパターンです。

私は同じことを、機能的な世界にとどまるために不変型でしかない、つまり、その機能が互換性のある型を実装するにはどうすればよいのですか?ユーザーが使用するpublic関数は同じです。

type 'a MyType = ... 

let func1 mytype = ... 
let func2 mytype -> int = ... 

MyTypeの定義は不明であり、後で変更することができます。より効率的なバージョンの関数が見つかった場合(コンテナタイプのより良い実装のように)、多くの努力やモジュール全体の再設計を必要としません。 1つの方法は、関数と識別された共用体でパターンマッチングを使用することですが、それはスケーラビリティが高いとは言えません。

+4

F#で同じことをしようとしているのは、クラスとインターフェイスを実装できるからです。 – kemiller2002

+1

はい。 1つの可能性は、デザイン全体をC#からF#にコピーすることですが、基本となる実装は派生クラスの一部でなければなりません。コンテナで動作する関数は、 'container.IsEmpty'を呼び出しますか?そして 'let add ... ='がオブジェクトの状態を変更しないようにクラス/タイプをどのように設計できますか? – NordCoder

+4

F#でOOPを実行しようとしているのか、機能レンズを通して問題を再考しているのかは不明です。あなたはインターフェイスが何をしたいのですが、F#の慣習的なやり方で、あるいはコード内にリテラルインターフェイスを必要としていますか? –

答えて

2

OO言語よりはるかに単純な型を使用する方が、関数型言語ではより一般的です。

図形のモデリングは古典的な例です。 、我々が導入する可能性、それはこのアプローチを使用して新しいタイプを追加することは非常に簡単だということ

type IShape = 
    abstract member Area : double 

type Circle(r : float) = 
    member this.Area = System.Math.PI * r ** 2.0 
    interface IShape with 
     member this.Area = this.Area 

type Rectangle(w : float, h : float) = 
    member this.Area = w * h 
    interface IShape with 
     member this.Area = this.Area 

お知らせTriangleまたは比較的少ない労力でHexagonクラス:

はここで、一般的なオブジェクト指向のアプローチです。型を作成してインターフェイスを実装するだけです。

対照的に、新しいPerimeterメンバーをIShapeに追加する場合は、多くの作業が必要になる可能性があるすべての実装を変更する必要があります。今

我々は関数型言語で形状をモデル化する方法を見てみましょう:、うまくいけばあなたはそれが各Shapeケースに対して、我々は単にパターンマッチがperimeter機能を追加する方がはるかに簡単だと見ることができる今

type Shape = 
    |Circle of float 
    |Rectangle of float * float 

[<CompilationRepresentation (CompilationRepresentationFlags.ModuleSuffix)>] 
module Shape = 
    let area = function 
     |Circle r -> System.Math.PI * r ** 2.0 
     |Rectangle (w, h) -> w*h 

とコンパイラはすべてのケースで徹底的に実装しているかどうかを確認できます。

対照的に、Shapeで動作するすべての機能を元に戻す必要があるため、新しいShapeを追加するのははるかに難しいです。

結論として、使用するモデリングの形式は問わず、トレードオフがあります。この問題は式の問題と呼ばれます。


あなたのContainer問題への第二のパターンを簡単に適用できます。

ここ
type Container = 
    |ContainerA 
    |ContainerB 

let containerFunction1 = function 
    |ContainerA -> .... 
    |ContainerB -> .... 

あなたが二つ以上の例を持つ単一のタイプがあり、それぞれのケースのための機能のユニークな実装がモジュールに含まれています関数ではなく、型そのものです。

+0

私はOOとFPのパラダイムの間のトレードオフの観点が好きで、表現の問題を認識していませんでした。ありがとう!他の有用なコメント作成者に感謝します。 – NordCoder

+1

@ NordCoder問題には他にも解決策があることは注目に値する。あなたがアドホック多型(すなわち、タイプ - クラス/形質)のための良いシステムを持っているなら、それは別の選択肢を開きます。 .NETは、現時点でそれらをサポートしていませんが、実装の仕組みが最近実証されました。 – TheInnerLight

+0

私はそれを認識しています。実際には私のF#コードは、これを達成するために型抜きを使用するHaskellライブラリに触発されています。 F# "typeclass"の実装は、Haskellのものに比べて少し制限があるが、私が間違っていれば私を修正することは私の理解である。 – NordCoder

関連する問題