2016-07-16 5 views
0

関数のパラメータとして機能する関数値を呼び出すにはどうすればよいですか?関数のパラメータとして機能する関数値を呼び出すにはどうすればよいですか?

具体的には、私の目標は、パラメータが実際に関数である関数のパラメータを利用することです。

私の場合、データを記録するためのインターフェイスを実装しようとしています。

は、ここに私のコードです:

let logToFile (filePath:string) (message:string) = 
    let file = new System.IO.StreamWriter(filePath) 
    file.WriteLine(message) 
    file.Close() 

let makeInitialDeposit deposit = 
    let balance = deposit |> insert [] 
    sprintf "Deposited: %f" balance 

let logDeposit deposit (log:'medium ->'data -> unit) = 
    deposit |> makeInitialDeposit 
      |> log 

注次の関数:

let logDeposit deposit (log:'medium ->'data -> unit) = 
    deposit |> makeInitialDeposit 
      |> log 

私は、ログ機能のコンパイルエラーを取得:

この原因を構築します指示よりも一般的でないコードタイプ注釈の タイプ変数 'medium'は タイプ 'string'に制限されています。

私はmakeInitialDepositが文字列を返すと理解します。 しかし、その文字列型はジェネリック型のデータにマップされます。 したがって、ジェネリックはどんなタイプのものでも構いませんか?

私はその後、培地(すなわちファイル)の引数を供給しようとした:

let logDeposit deposit (log:'medium ->'data -> unit) medium = 
    deposit |> makeInitialDeposit 
      |> log medium 

その後、私のエラーはにアップデートしまった:この構築物は、コードが示されているよりも、一般的なことになり

タイプ注釈の 型変数 'dataは 型' string 'に制限されています。

私の目標

最終的に、私は、ログと呼ばれるインタフェースを持っており、そのインターフェイス(すなわちlogToFile)の実装に渡したいです。

最初の解釈に基づいてコンパイルエラーをどのように解釈するべきかに関するガイダンスはありますか?

挿入機能の依存関係

let getBalance coins = 
    coins |> List.fold (fun acc d -> match d with 
            | Nickel   -> acc + 0.05 
            | Dime   -> acc + 0.10 
            | Quarter  -> acc + 0.25 
            | OneDollarBill -> acc + 1.00 
            | FiveDollarBill -> acc + 5.00) 0.00 

let insert balance coin = 
    coin::balance |> getBalance 
+0

ありがとうございました。私は、セミコロンの挿入と削除の実装を追加しました。 –

答えて

2

問題はlog :'medium ->'data -> unitと定義されています。

次に、タイプstringdeposit |> makeInitialDepositの結果を取り出し、log関数にパイプします。論理的にコンパイラは、'medium = stringを推論します。

あなたlogDeposit機能で'medium引数を受け入れるなら、あなたは、単に手順に沿ってその推論を移動し、deposit |> makeInitialDepositは今もそうstring'data = stringです。


は、私はあなたがこれらの機能はよくあなたのドメインをモデル化していないし、あなたのロギングロジックはあなたのコードの残りの部分に出て出血しているのでかかわらず、苦労していると思います。

なぜmakeInitialDepositstringを返しますか?

なぜgetBalancefloatを返すが、そのbalance引数としてCoin listinsert受け付けていますか?

私は3つの引数を受け入れロギング機能を作ることから始めます:

let logToFile (filePath:string) (formatf : 'data -> string) data = 
    use file = new System.IO.StreamWriter(filePath) 
    file.WriteLine(formatf data) 
    data 

それはfilePath : string -> (formatf : 'data -> string) -> (data : 'data) -> dataを入力しています。ログへのパスを受け取ります。タイプは'data、文字列は'dataとなり、ファイルに記録されます。最後に、あなたが変更しなかった引数dataを返します。つまり、原則として、コード内の任意の値のロギングを任意の場所に挿入できます。

私は、このようなドメイン内の一部の機能を設定します。

let valueOf = function 
    | Nickel   -> 0.05m 
    | Dime   -> 0.10m 
    | Quarter  -> 0.25m 
    | OneDollarBill -> 1.00m 
    | FiveDollarBill -> 5.00m 

let totalValue coins = 
    coins |> List.fold (fun acc coin -> acc + valueOf coin) 0.0m 

let insert coins coin = coin::coins // returns Coin list 

let makeInitialDeposit deposit = insert [] deposit // returns Coin list 

私はその後、任意の時点でロギングを挿入し、これらの機能を使用することができます。

let balance = 
    makeInitialDeposit OneDollarBill 
    |> logToFile "file.txt" (sprintf "Initial Deposit: %A") 
    |> totalValue 
    |> logToFile "file2.txt" (sprintf "Balance : $%M") 

このアプローチは、あなたがログをフィットすることができますロギングの周りにドメインを構築するのではなく、ドメインの周りに

+0

TheInnerLightに感謝します。あなたは私の質問の要点に答えました。最終的には、logTofileをlogという高次関数に置き換え、log関数の値からlogToFileを呼び出す方法を見つけようと苦労していました。 –

+0

@ScottNimrodロギングのために 'data'を' string'に変換するには、特別な 'formatf'関数が必要です。部分的なアプリケーションを使ってあらかじめ定義された型のロギングを作成することもお勧めします。一般的に使われている型の '' data - > string''変換関数を与えて、同じデータ型を記録したいときはいつでも再利用することができます。 – TheInnerLight

+0

好奇心を要して、私が購読できるブログがありますか?私はこの言語に関するあなたの専門知識に本当に感謝しています。 –

1

まず第一に、あなたがあなたのパス名として"Deposited: 0.25"ような文字列で渡していることを奇妙に思えます。おそらく、最初のパラメータにmessageを、logToFileの2番目のパラメータにfilePathを設定します。したがって、log'data -> 'medium -> unitとなります。

コンパイルエラーの問題は、makeInitialDepositが文字列を返し、その結果をlogにパイプしたときに制約が発生するということです。それが動作するように取得するための一つの方法は、このような'dataに文字列を変換するためにlogDepositに別のパラメータを追加することです:

let logDeposit deposit (log: 'data ->'medium-> unit) (stringConverter: string -> 'data) = 
    deposit |> makeInitialDeposit 
      |> stringConverter 
      |> log 

let dummyLog (a:int) (b:string) =()のように、この何かを使用すると、intに文字列から適切なコンバータに渡すと仮定していきます。

+0

別の方法がありますか?なぜ文字列は法的な型ではないのですか?なぜこのジェネリックは突然文字列型のことを気にするのでしょうか? –

+0

あなたが指定した最小限の例を使用すると、stringは有効な型です。実際には、stringは '' data''の型を制約します。それがあなたにとって起こっていない場合、何か他のことが起こっています。 – Ringil

+0

私が尋ねようとしているのは、一般的な入力値に文字列コンバータが必要なのはなぜですか?さらに、回答として選択する前に、コミュニティからこの回答を投票していただきたいと思います。これまでのところ、私はあなたの答えをアップアップしました。 –

関連する問題