2017-05-12 10 views
3

私は小さなプロジェクトに取り組んでおり、機能的な方法でF#を学習しようとしています。乱数を生成することができず、乱数を得ることができない奇妙な理由があります。ここに私のF#コードはLET乱数を生成できませんF#

let IfancyHerList = [("Sara",1); ("Saima",2); ("Zoe",3);("Scarlett",4); 
("Jennifer",5);("Sandra Bullock",6)] 

let MyGirlFriend = List.pick (fun funToNight -> 
        let n = rand.Next(10) 
        match funToNight with      
        | (value,n) -> Some value 
        |_ -> None) IfancyHerList 
printfn "Your date for tonight is %s lucky fella" MyGirlFriend 

はn = rand.Next(10)は、乱数を生成しますが、一致ブロック

内の任意の提案が

おかげ

+0

この乱数のAPIは関数型プログラミングと互換性がないためです。あなたの擬似乱数ジェネレータは、適切な関数プログラムでは 'next'への引数として渡す必要があり、結果として' pair <> 'で数値と新しい変更状態を取得する暗黙の状態を持っています。あなたは最初にそれをしたくないはずです。 –

+0

あなたは私の答えを受け入れましたが、David Raabの答えははるかに大きかったです。[F#:Matching .. with]と重複する可能性があります(http://stackoverflow.com/questions/38711655/f-not-understanding-match-with) – rmunn

+0

コンプリート。私はあなたが私の答えを受け入れるべきではなく、代わりに彼を受け入れるべきだと感じています。 – rmunn

答えて

6

あなたのコードは、あなたが期待することをしません。パターンマッチングは、技術的にデータを構築することの反対です。それは単にデータを分解/分解する。 funToNightがタプルの場合

  1. チェック:あなたはここで何

    match funToNight with      
    | (value,n) -> Some value 
    |_ -> None 
    

    は、次のような意味を持っています。

  2. は、あなたが期待したものと思われるn

value

  • 割り当てるために、タプルの第2の値をタプルの最初の値を割り当てた:

    1. チェックした場合の第二の値タプルは内部にありますn

    これはパターンマッチングとは異なりますrks。

    パターンマッチングにwhen句を追加することで、値と既定の変数を比較するなどの条件を追加できます。このように:

    match funToNight with 
    | (value,x) when x = n -> Some value 
    | _ -> None 
    

    私の意見では、あなたのケースは、まさにパターンマッチングが意味をなさない場合です。 2番目のエントリが自分の乱数であるかどうかを確認したいので、代わりにif文を使用します。

    let MyGirlFriend = 
        List.pick (fun funToNight -> 
         let n = rand.Next(10) 
         if (snd funToNight) = n 
         then Some (fst funToNight) 
         else None 
        ) IfancyHerList 
    

    の代わりに、fstsndあなたもラムダでそれを行うことができます。

    let MyGirlFriend = 
        List.pick (fun (name,nr) -> 
         let n = rand.Next(10) 
         if nr = n 
         then Some name 
         else None 
        ) IfancyHerList 
    

    これは他のサイズのタプルでも動作する一般的な解決方法です。fstsndは、正確に2つの要素を持つタプルでのみ動作します。

    さらに、List.pickの代わりにList.tryPickを使用します。 List.pickは、要素が見つからない場合に例外をスローします。先頭の変数は小文字で始まる必要があります。タイプ/クラスには大文字の値が使用されます。だからここ

    は完全な作業例です:

    let rand = new System.Random() 
    
    let ifancyHerList = 
        [ 
         ("Sara",1); ("Saima",2); ("Zoe",3); ("Scarlett",4); 
         ("Jennifer",5);("Sandra Bullock",6) 
        ] 
    
    let myGirlFriend = 
        List.tryPick (fun (name,nr) -> 
         let n = rand.Next(10) 
         if nr = n 
         then Some name 
         else None 
        ) ifancyHerList 
    
    match myGirlFriend with 
    | Some name -> printfn "Your date for tonight is %A lucky fella" name 
    | None  -> printfn "You don't have a date tonight!" 
    

    補遺

    あなたList.pick呼び出しが非常に多くNoneを返し、エントリを選択しません。理由は、List.pickに渡すラムダ関数の内部で乱数を生成するためです。

    コードの現在の "フロー"は、このようなものです。あなたはリストを通過します。最初にピッキングする("Sara",1)。ランダムに生成すると、5としましょう。 15が一致しないので、次のエントリ("Saima", 2)が使用されます。しかし、新たな乱数を生成すると、3とし、32が等しくないため、次のエントリが選択されたとしましょう。これはすべての項目を選択することなく続行できます。ランダム生成をrand.Next(6)に変更した場合でも

    したがって、ラムダ式に副作用を追加しないでください。私はあなたが1つの乱数を生成し、それをリストから選びたいと思っています。ラムダの外側でランダムな呼び出しを抽出することで簡単に変更できます。

    let myGirlFriend = 
        let n = rand.Next(10) 
        List.tryPick (fun (name,nr) -> 
         if nr = n 
         then Some name 
         else None 
        ) ifancyHerList 
    

    一般的なアドバイスでは、高次関数の副作用は避けてください。

  • +0

    Davidは頭脳を少し入れ替えることができます。12週間後にこれをとてもうまく説明しましたが、私は関数型プログラミングが何であるかを理解する必要があります。ありがとうございました。問題が解決しました。 – Wazzie

    +0

    @WaheedRafiq別の問題の補遺を追加しました。 –

    5
    最も歓迎されるであろうではありません

    あなたの本当の問題は乱数ではありません。それはあなたのmatch声明です。あなたはそれがどのように動作するか誤解します。短いバージョン:match (whatever) with (value, n) -> ...は、あなたの考えていることを実行しません。常に一致し、一致したタプルの2つの部分に名前valuenを割り当てます。

    より長いバージョンは、F#: Not understanding match .. withと同じ間違いをしているので、もっと深い答えを読むためにその質問を指摘します。