2017-02-08 11 views
3

以下のaddValues関数を書く方が良いでしょうか?それは、FSharp.Reflectionではなくパターンマッチングを使用することが可能になるはずですが、私はそれを見ることができません。既存のケースから新しいユニオンケースを作成する

open System 
open FSharp.Reflection 

type Value = 
    | Tag1 of decimal 
    | Tag2 of decimal 
    | Error of string 

let addValues v1 v2 = 
    let c1, f1 = FSharpValue.GetUnionFields(v1, v1.GetType()) 
    let c2, f2 = FSharpValue.GetUnionFields(v2, v2.GetType()) 
    let amt1 = (f1.[0]) :?> decimal 
    let amt2 = (f2.[0]) :?> decimal 

    if c1 = c2 
     then ((FSharpValue.MakeUnion(c1, [|box (amt1 + amt2)|]))) :?> Value 
     else Error "Mixed Tags" 

これがそうのように使用することができます。

addValues (Tag1 22m) (Tag1 10m) //Value = Tag1 32M 
addValues (Tag1 22m) (Tag2 10m) //Value = Error "Mixed Tags" 
+2

'addValues(Error" e1 ")(Error" e2 ")'ではどうなるでしょうか? – Lee

+1

このタイプに 'Error'が必要ですか? –

+1

この場合、私にとっては、['Choice <'T1,'T2>'](https://msdn.microsoft.com/visualfsharpdocs/conceptual/core.choice%5B%27t1%2C%27t2%5D-union-%5Bfsharp% 5D)または多分 'Option' –

答えて

5

それはaddValues (Error "e1") (Error "e2)がどのように処理すべきか明確ではないのですが、あなたが行うことができ、他の例のために:

let addValues v1 v2 = 
    match v1, v2 with 
    | Tag1 d1, Tag1 d2 -> Tag1 (d1 + d2) 
    | Tag2 d1, Tag2 d2 -> Tag2 (d1 + d2) 
    | Error e1, Error e2 -> //??? 
    | _ -> Error "Mixed Tags" 
+0

"一致するすべてのタグを列挙しないで "指定しておくべきです。基本的には、2つのケースが同じかどうかをチェックし、その場合は合計で新しいケースを返します。それ以外の場合はエラーを返します。 2つの値がエラーの場合は、いずれかのエラーを返す場合は私のドメインで正常です。 – jbeeko

4

これは、正確に何ではありません元の質問は約でしたが、他のコメント作成者のように、あなたのデータ型が実際にはうまく選ばれていないことに気付きました。 Errorの大文字と小文字を区別すると、より多くのタグを持っている瞬間にaddValues関数が本当に扱いにくくなります。

type Tag = | Tag1 | Tag2 
type ResultOrError = | Result of Tag * decimal | Error of string 

を(またはChoiceタイプのいずれかを使用します):私はすべてあなたの値は、小数点であると仮定した場合、あなたは次のように再定義することができます。 addValuesは、次のようになります。

let addValues t1 t2 = 
    match t1, t2 with 
    | Result (tag1, v1), Result (tag2, v2) when tag1 = tag2 -> Result (tag1, v1 + v2) 
    | Result _, Result _ -> Error "Tag mismatch" 
    | Result _, Error _ -> failwith "not implemented" 
    | Error _, _ -> failwith "not implemented" 

あなたのタグを拡張した瞬間は、type Tag = | Tag1 | Tag2 | Tag3に入力し、addValuesはまだ働いまま。

+0

これは私がやっている別のデザインです。 'Tag1 33m'と書くだけで、あなたは 'Result(Tag1、33m)'と書く価値があります。 – jbeeko

1

Anton Schwaighofer in his answerと同じトランペットを吹きたいです。重要な情報は、モナド技術を利用してthe liftingを実行するため、データ構造の内部になければなりません。別の方法では、ケースTag1Tag2のコンストラクタを別々に呼び出す必要があります。

type Tag = Tag1 | Tag2 
type ResultOrError = 
| Result of Tag * decimal 
| Error of string 

let bind2 f = function 
| Result(tag, value) -> f tag value 
| error -> error 
let lift2EqualTag op mx my = 
    bind2 (fun tagX x -> 
     bind2 (fun tagY y -> 
      if tagX = tagY then Result(tagX, op x y) 
      else Error "Mixed tags") my) mx 
let add = lift2EqualTag (+) 

add (Result(Tag1, 22m)) (Result(Tag1, 10m)) 
// val it : ResultOrError = Result (Tag1,32M) 
add (Result(Tag1, 22m)) (Result(Tag2, 10m)) 
// val it : ResultOrError = Error "Mixed tags" 
関連する問題