2016-06-21 5 views
5

は、私は次のエラーF#で申請者をするには?

let y() = Success (fun x -> x + 1) <*> (Success 3);; 
-----------^^^^^^^^^^^^^^^^^^^^^^^^ 
/Users/robkuz/stdin(473,12): error FS0001: Type constraint mismatch. 
The type 
    Result<'a,'c> 
is not compatible with type 
    Result<('a -> 'b),'c> 
The resulting type would be infinite when unifying ''a' and ''a -> 'b' 
を取得し、次の型とメンバ関数

type Result<'TSuccess, 'TError> = 
    | Success of 'TSuccess 
    | Error of 'TError list 
    with 
    member this.apply fn = 
     match (fn, this) with 
     | Success(f), Success(x) -> Success(f x) 
     | Error(e), Success(_) -> Error(e) 
     | Success(_), Error(e) -> Error(e) 
     | Error(e1), Error(e2) -> Error(List.concat [e1;e2]) 

と、次のインライン関数

let inline (<*>) (f: ^A) (t:^A) = 
    let apply' = (^A : (member apply : ^A -> ^A) (t, f)) 
    apply' 

そして、この呼び出しサイト

let y() = Success (fun x -> x + 1) <*> (Success 3) 

を考えます

この全体のことはHaskells Applicativeのをエミュレートしようとする試みであり、署名が

(<*>) :: forall f a b. Apply f => f (a -> b) -> f a -> f b 

でなければなりません。しかし、私は、F#

それが起こるようにする方法上の任意のアイデアをでそれを表現する方法はありません私の知る限りいけませんか?

+0

@Thomasが提供するソリューションは問題ありませんが、プリミティブ型(リスト、配列、オプション)では動作しません。また、モナドと自動的には動作しません。 [もっと完全な解決策](https://github.com/gmpl/FsControl/blob/master/FsControl.Core/Functor.fs#L133)です。 – Gustavo

答えて

7

一般に、F#でハスケルパターンをエミュレートしようとするのは良い考えではないと思います。ハスケルでは、モナドやアプリケーションが頻繁に使用されるため、コードの多くは非常に一般的なものとして書かれています。

F#では、モナドやアプリケーションに対して多型のコードを記述する必要がなく、何が起こっているのかを簡単に確認できるため、より専門化されたコードを作成することをお勧めします。だから、私はこれまでF#で実際に "適用可能"以上に働く<*>演算子を書こうと思っているとは思わない。

あなたのコードの問題は、<*>オペレータが引数と結果の両方に同じタイプのパラメータを使用していることです(コールでは異なるタイプです)。3つの別々のタイプのパラメータを使用するとうまく動作します:

let inline (<*>) (f: ^B) (t:^A) : ^C = 
    let apply' = (^A : (member apply : ^B -> ^C) (t, f)) 
    apply' 
関連する問題