かなりお願いしているようです。文字列操作の理解はあなたに任せますが、一連の操作を並行して実行する演算子を定義する方法を紹介します。
ステップ 1:fuse
関数を作成する
ヒューズ関数は、複数の関数を使用して単一の入力をマップするように見えます。これは、次のように簡単に記述できます。
//val fuse : seq<('a -> 'b)> -> 'a -> 'b list
let fuse functionList input = [ for f in functionList -> f input]
すべてのマッピング関数が同じタイプである必要があることに注意してください。
ステップ 2: 関数を並列実行する演算子を定義する
標準の平行マップ関数は、次のように記述できます。
//val pmap : ('a -> 'b) -> seq<'a> -> 'b array
let pmap f l =
seq [for a in l -> async { return f a } ]
|> Async.Parallel
|> Async.RunSynchronously
私の知る限り、Async.Parallel
非同期操作を並行して実行します。ここで、特定の時間に実行される並行タスクの数は、マシン上のコアの数と同じです (間違っている場合は誰かが私を修正できます)。したがって、デュアル コア マシンでは、この関数が呼び出されたときにマシン上で最大 2 つのスレッドが実行されている必要があります。コアごとに複数のスレッドを実行してもスピードアップは期待できないため、これは良いことです (実際には、余分なコンテキストの切り替えにより速度が低下する可能性があります)。
とで演算子を定義でき|>>
ます。pmap
fuse
//val ( |>> ) : seq<'a> -> seq<('a -> 'b)> -> 'b list array
let (|>>) input functionList = pmap (fuse functionList) input
そのため、|>>
オペレーターは一連の入力を取得し、さまざまな出力を使用してそれらをマッピングします。これまでのところ、これらすべてをまとめると、次のようになります (fsi で)。
> let countOccurrences compareChar source =
source |> Seq.sumBy(fun c -> if c = compareChar then 1 else 0)
let length (s : string) = s.Length
let testData = "Juliet is awesome|Someone should give her a medal".Split('|')
let testOutput =
testData
|>> [length; countOccurrences 'J'; countOccurrences 'o'];;
val countOccurrences : 'a -> seq<'a> -> int
val length : string -> int
val testData : string [] =
[|"Juliet is awesome"; "Someone should give her a medal"|]
val testOutput : int list array = [|[17; 1; 1]; [31; 0; 3]|]
testOutput
には 2 つの要素が含まれており、どちらも並行して計算されています。
ステップ 3: 要素を単一の出力に集約する
よし、これで配列の各要素で表される部分的な結果が得られたので、部分的な結果を 1 つの集計にマージしたいと考えています。入力の各要素は同じデータ型であるため、配列の各要素を同じ関数にマージする必要があると思います。
これは私が仕事のために書いた本当に醜い関数です:
> let reduceMany f input =
input
|> Seq.reduce (fun acc x -> [for (a, b) in Seq.zip acc x -> f a b ]);;
val reduceMany : ('a -> 'a -> 'a) -> seq<'a list> -> 'a list
> reduceMany (+) testOutput;;
val it : int list = [48; 1; 4]
reduceMany
長さ n のシーケンスのシーケンスを取り、長さ n の配列を出力として返します。この関数を書くためのより良い方法を考えることができるなら、私のゲストになってください:)
上記の出力をデコードするには:
- 48 = 2 つの入力文字列の長さの合計。元の文字列は 49 文字でしたが、「|」で分割されていることに注意してください。"|" ごとに 1 文字を消費しました。
- 1 = 入力内の「J」のすべてのインスタンスの合計
- 4 = 'O' のすべてのインスタンスの合計。
ステップ 4: すべてをまとめる
let pmap f l =
seq [for a in l -> async { return f a } ]
|> Async.Parallel
|> Async.RunSynchronously
let fuse functionList input = [ for f in functionList -> f input]
let (|>>) input functionList = pmap (fuse functionList) input
let reduceMany f input =
input
|> Seq.reduce (fun acc x -> [for (a, b) in Seq.zip acc x -> f a b ])
let countOccurrences compareChar source =
source |> Seq.sumBy(fun c -> if c = compareChar then 1 else 0)
let length (s : string) = s.Length
let testData = "Juliet is awesome|Someone should give her a medal".Split('|')
let testOutput =
testData
|>> [length; countOccurrences 'J'; countOccurrences 'o']
|> reduceMany (+)