Subscribed unsubscribe Subscribe Subscribe

F# Monkey

about

(ポエム)テキストエディタとビール

Vim Food

f:id:callmekohei00:20170329115027p:plain

あれもこれもと言うけどさ
大人の事情だと言うけどさ
そうじゃないんだ


頭がいいとか悪いとか
賢しいとか要領がとか
そうじゃないんだ


泥臭く泥臭く
まっさらなエディタの上に
コードを書いて実行をして


自分がしたいことを
表現してみせるんだ
テキストエディタで


人も景色も変わるけど
今日も元気だ
ビールがうまい
Remove all ads

F# on RX

F#

f:id:callmekohei00:20170325142408p:plain

Prepare01 ( Library )

source https://www.nuget.org/api/v2

nuget FSharp.Control.Reactive

Prepare02 ( required )

F#のコードにRxライブラリを取り込むのはこんな感じ

#r @"./packages/FSharp.Control.Reactive/lib/net45/FSharp.Control.Reactive.dll"

open System                  // System.EventArgs, System.Timers.ElapsedEventArgs
open System.Reactive.Linq    // IGroupedObservable
open FSharp.Control.Reactive // Observable methods

Rx overview

Rxの勘所〜

IObservable<'T> とは string とか List とかと同じタイプの一種

IObservable<string><string> とは IObservable の中身が string ということ

"Hello" という string を IObservable<string> にするには Observable.single "hello world"

Intro

Rxとはこんな感じ〜

// プリント関数
let oStdout ( obs:IObservable<'T> ) = 
    obs
    /// 全てのIObservableに対しての操作が終わったら`-----`を印字する
    |> Observable.finallyDo( fun _ -> stdout.WriteLine("-------------") )
    /// IObservableを印字する
    |> Observable.subscribe( fun x -> stdout.WriteLine(x) )


Observable.single "hello world"
|> oStdout

Observable.single "hello world"
|> Observable.map ( fun s -> s.ToUpper() )
|> oStdout

Observable.single "hello world"
|> Observable.concat ( Observable.single "callmekohei" )
|> oStdout

結果

hello world
-------------
HELLO WORLD
-------------
hello world
callmekohei
-------------

Event with Rx

IEvent<_>IObservable<_>と同じ感覚でオーケー

// イベントをインスタンス化
let e = Event<_>()

// イベントを実体化する
e.Publish
// イベントハンドラを登録する
// イベントハンドラとはイベントを実行するときに行う操作のこと
|> Observable.add( fun (e:string) -> stdout.WriteLine(e) )

// イベントを実行する
e.Trigger("hello world")

結果

hello world


IEvent<ElapsedEventHandler,ElapsedEventArgs>IObservable<_>と同じ感覚でオーケー

/// file name is timer.fsx
open System.Timers

// イベントをインスタンス化
let timer = new Timer(1000.)

/// イベントを実体化
timer.Elapsed
/// イベントハンドラを登録
|> Observable.add (fun (e:ElapsedEventArgs) -> printfn "%A"( e.SignalTime ))

// イベントを実行(1000msごとにイベントを実行する)
timer.Start()

stdout.WriteLine("please enter key...")

/// dispose method call
stdin.ReadLine()
stdout.WriteLine("dispose method call.")

/// イベントを破棄する(メモリクリアする)<--- これ重要!
timer.Disposed

結果

$ fsharpi timer.fsx 
please enter key...
3/25/2017 1:41:42 PM
3/25/2017 1:41:43 PM
3/25/2017 1:41:44 PM
3/25/2017 1:41:45 PM
3/25/2017 1:41:46 PM

dispose method call.

Observable methods

いろいろなメソッド〜

//----------------------------------------------------------------------------
// single, toObservable and generate
//

"hello world"
|> Observable.single
|> oStdout
/// hello world

["hello world"]
|> Observable.toObservable
|> oStdout
/// hello world

Observable.generate 0 (fun i -> i < 3) ( fun i -> i + 1 ) ( fun i -> i * i )
|> oStdout
/// 0
/// 1
/// 4


//----------------------------------------------------------------------------
// apply, defer
//

["hello world"]
|> Observable.toObservable
|> Observable.apply ( Observable.toObservable ( [fun s -> s.ToUpper()] ) )
|> oStdout
/// HELLO WORLD

fun _ -> Observable.single "hello world"
|> Observable.defer
|> oStdout
/// hello world


//----------------------------------------------------------------------------
// map, collect, flatmap and filter
//

"hello world"
|> Observable.single
|> Observable.map ( fun s -> s.ToUpper() )
|> oStdout
/// HELLO WORLD

["hello world"]
|> Observable.toObservable
|> Observable.thenMap ( fun s -> s.ToUpper() )
|> fun x -> [x]
|> Observable.joinWhen
|> oStdout
/// HELLO WORLD

["hello";"world"]
|> Observable.collect (fun s -> Observable.single ( s.ToUpper() ) )
|> oStdout
/// HELLO
/// WORLD

["hello";"world"]
|> Observable.toObservable
|> Observable.flatmap (fun s -> Observable.single ( s.ToUpper() ) )
|> oStdout
/// HELLO
/// WORLD

["hello";"world"]
|> Observable.toObservable
|> Observable.filter (fun s -> s = "hello" )
|> oStdout
/// hello


//----------------------------------------------------------------------------
// concat 
//

Observable.single "hello"
|> Observable.concat ( Observable.single "world" )
|> oStdout
// hello
// world


//----------------------------------------------------------------------------
// iter, finallyDo 
//

["hello";"world"]
|> Observable.toObservable
|> Observable.iter ( fun _ -> stdout.WriteLine("---------") )
|> oStdout
/// ---------
/// hello
/// ---------
/// world


["hello";"world"]
|> Observable.toObservable
|> Observable.finallyDo ( fun _ -> stdout.WriteLine("---------") )
|> oStdout
/// hello
/// world
/// ---------


//----------------------------------------------------------------------------
// reduce and fold 
//

["hello";"world"]
|> Observable.toObservable
|> Observable.reduce ( fun a b -> a + " " + b )
|> oStdout
/// hello world

["hello";"world"]
|> Observable.toObservable
|> Observable.fold ( fun acc s -> acc + " " + s |> fun s -> s.TrimStart(' ') ) ""
|> oStdout
/// hello world


//----------------------------------------------------------------------------
// zip
//

(Observable.single "hello", Observable.single "world")
||> Observable.zip
|>  oStdout
/// (hello, world)



//----------------------------------------------------------------------------
// repeatCount
//

["I";"want";"to";"eat";"icecream"]
|> Observable.toObservable
|> Observable.repeatCount 2
|> Observable.subscribe( fun (obs:IObservable<string>) ->
    obs |> Observable.subscribe( fun obs' -> stdout.WriteLine(obs') ) |> ignore
    () )

/// I
/// want
/// I
/// to
/// want
/// eat
/// to
/// icecream
/// eat
/// icecream


//----------------------------------------------------------------------------
// groupBy
//

["hello";"world";"callmekohei"]
|> Observable.toObservable
|> Observable.groupBy ( fun s -> s.Length < 6 )
|> Observable.subscribe ( fun (g:IGroupedObservable<bool,string>) -> stdout.WriteLine( string(g.Key) , g |> oStdout))
/// True
/// hello
/// world
/// False
/// callmekohei


//----------------------------------------------------------------------------
// others
//

["hello";"world"]
|> Observable.toObservable
|> Observable.head
|> oStdout
/// hello

["hello";"world"]
|> Observable.toObservable
|> Observable.first
|> oStdout
/// hello

["hello";"world"]
|> Observable.toObservable
|> Observable.last
|> oStdout
/// world

["hello";"world"]
|> Observable.toObservable
|> Observable.elementAt 1
|> oStdout
/// world

["hello";"world"]
|> Observable.toObservable
|> Observable.contains "hello"
|> oStdout
/// True

["hello";"world"]
|> Observable.toObservable
|> Observable.exists ( fun s -> s = "hello" )
|> oStdout
/// True

["hello";"world"]
|> Observable.toObservable
|> Observable.count 
|> oStdout
/// 2

["hello";"world";"hello";"world"]
|> Observable.toObservable
|> Observable.distinct 
|> oStdout
/// hello
/// world

Observable.range 1 10 
|> Observable.skip 3
|> Observable.take 3
|> oStdout
// 4
// 5
// 6

Observable.range 1 10
|> Observable.skipWhile( fun i -> i < 5 )
|> Observable.takeWhile( fun i -> i < 10 )
|> oStdout
// 5
// 6
// 7
// 8
// 9

Observable.range 1 10
|> Observable.maxOf
|> oStdout
/// 10


Observable.range 1 10
|> Observable.all ( fun n -> n % 2 = 0 )
|> oStdout
// False

Observable.empty 
|> Observable.any 
|> oStdout
// False


//----------------------------------------------------------------------------
// error raise
//

Observable.throw ( exn "エラーだよ" )
|> oStdout
/// エラーだよ

Observable methods ( async )

いろいろなメソッド〜 その2( async )




    
  
Remove all ads

F#言語を使ってロト6を当ててみる!(予測編)

F#

f:id:callmekohei00:20170319155858p:plain

Summary

データーベースSqliteに保存されてる当選番号をもとに予測する

まずは・・・

スロットという考え方

たとえば 01 09 11 24 29 42 という当選番号は下記のように考えます

スロット1  01
スロット2  09
スロット3  11
スロット4  24
スロット5  29
スロット6  42

ゾーンという考え方

ロト61から43までの数字を3つに区分します

ゾーン1  01 - 15
ゾーン2  16 - 30
ゾーン3  31 - 43

予測の方法

ランダムリストの作成

過去の当選番号をスロットごとにリスト化します

スロット毎に数字をランダムに選びます

スロット1で`10`を選んだらスロット2は`11`以上の数字をランダムに選びます

ランダムリストの選別

ゾーンをランダムに作成します(たとえば`2 1 3`)

先ほど作成したランダムリストから、先ほど作成したゾーンに適合するもののみフィルターします

5個のランダムリストを選びます

あたるかどうか

わかりませんwww

一応コード

こんな感じ

module Main =
    open Util
    
    /// (STEP1) 各スロットごとの数字をリストにまとめる

    let cq = new ConcurrentQueue<int list>()
            
    let s = @"SELECT * FROM loto6"

    let f2 = fun (r:SQLiteDataReader) -> 
        [2..7]
        |> List.map( fun n -> r.GetInt32(n) )
        |> fun l -> cq.Enqueue l
        |> ignore
    
    let data =    
        let db = SQ3( sqlite_connection )
        db.sqlite_open
        db.sqlite_select s f2 
        cq.ToArray() |> Array.toList |> swapRowColumn

    
    /// (STEP2) 各ゾーンの個数にもとづいて予測する
    
    let idea04 (loto:Loto) (n:int) =

        let zone = createZone loto

        Seq.initInfinite (fun _ -> createAscendantRandomList data )
        |> Seq.filter (fun l -> toZone loto l = zone )
        |> Seq.distinct
        |> Seq.take n

    idea04 loto6 5
    |> Seq.fold ( fun acc l -> prettyPrint " " l + "\n" + acc ) ""
    |> stdout.WriteLine


コードはこちらから〜

当たるも八卦当たらぬも八卦 · GitHub



Good Luck!

Remove all ads

F#言語を使ってロト6を当ててみる!(データーベース登録編)

F#

f:id:callmekohei00:20170319150912p:plain

Summary

取得した当選番号をデーターベースSqliteに保存する

First Step

FSharp.Data, System.Data.SQLitenugetします

osxの人はここを参考にlibSQLite.Interop.dylibも用意します

F#からSQLiteをつかってみる を一読してF#からSqliteに対しての操作をつかんでください

Second Step

データーベースファイルをあらかじめ作成します

テーブル名をloto6とします

/// loto.sqlite3という名前のデーターベースファイルを作成
$ sqlite3 loto.sqlite3

/// カラムをid, date, n1~n6 として作成
/// id は key とします ( key は重複ができない値です )
sqlite> create table loto6 ( id int primary key, date text , n1 int, n2 int, n3 int, n4 int, n5 int, n6 int );

/// 作業を終了します
sqlite> .exit

Third Step

次のような感じで当選情報をデーターベースに登録します

webの当選情報の当選回数とデーターベースの`id`を比較します

不足してる当選情報のsqlを作成します

データーベースに登録します

当選情報とidの比較

最新のidをデーターベースから取得します

sqliteのメソッドは返り値を返さないのでConcurrentQueueを使って返り値を取得します

/// 最新のid をデーターベースから取得する関数
let lastID_sqlite (db:SQ3) : int =

    let cq = new ConcurrentQueue<_>()

    let str = @"SELECT id FROM loto6"

    let f = fun (r:SQLiteDataReader) -> 
        cq.Enqueue ( r.GetInt32(0) ) |> ignore

    db.sqlite_open
    db.sqlite_select str f
    db.sqlite_close 

    cq.ToArray()
    |> fun arr ->
        if Array.isEmpty arr
        then 0
        else Array.max arr

sqlの作成

/// みずほ銀行のホームページから取得した当選情報
["1157"; "2017/03/16"; "05"; "17"; "20"; "28"; "39"; "42"]

/// ↓↓↓↓↓↓↓

/// データーベースに登録するための文字列(sql)
"INSERT INTO loto6 ( id, date, n1, n2, n3, n4, n5, n6 ) VALUES ('1157','2017/03/16','05','17','20','28','39','42')"

sqlを作成する関数

/// データーベースに登録するための当選情報の文字列を作成する関数 
let atariList atariData : string list =
    let str = @"INSERT INTO loto6 ( id, date, n1, n2, n3, n4, n5, n6 ) VALUES ("
    atariData
    |> List.map( fun l -> l |> List.fold ( fun acc s -> acc + "," + "'" + s + "'" |> fun s -> s.TrimStart(',') ) "" )
    |> List.map( fun s -> str + s + ")" )

データーベースへの登録

データーベースに登録する関数

/// データーベースに当選番号情報を登録する関数
let register (db:SQ3) atariStringsList : unit =
    db.sqlite_open
    atariStringsList |> List.iter ( fun s -> db.sqlite_insert s )
    db.sqlite_close

Code

今回書いたコードはこちら〜

みずほ銀行のホームページから取得したロト6の当選番号情報をデーターベースに登録するスクリプト · GitHub

参考

www.dbonline.jp

qiita.com

Remove all ads

F#言語を使ってロト6を当ててみる!(当選番号取得編)

F#

f:id:callmekohei00:20170319095445p:plain

Summary

みずほ銀行のホームページから過去の当選番号を取得する

First Step

まずFSharp.Datanugetします

Second Step

こんな感じでデーター取得します

/// FSharp.Data.dll にパスをとおします
#r @"./packages/FSharp.Data/lib/net40/FSharp.Data.dll"
open FSharp.Data

/// 当選番号の書いてあるホームページアドレス
let url = @"http://www.mizuhobank.co.jp/takarakuji/loto/loto6/index.html"
/// 当選番号が書いてある css selector
let css = @"table.typeTK > tbody > tr > td.alnCenter.extension > strong"

/// HTMLを取得します 文字コードは utf-8 にしときます(文字化け対策)
Http.RequestString( url , responseEncodingOverride = "utf-8")

/// HTMLをF#で扱えるようにパース(構文解析)します
|> HtmlDocument.Parse

/// 当選番号が書いてある行を取り出します
|> fun doc -> doc.CssSelect( css )

/// 当選番号をとりだします
|> List.map ( fun n -> n.InnerText() )

/// ボーナス数字も含めた7つのくくりでリストをつくります
|> List.chunkBySize 7

/// ボーナス数字をカットします
|> List.map ( List.truncate 6 )

/// 表示します
|> List.iter( fun l -> printfn "%A" l )

結果

["05"; "17"; "20"; "28"; "39"; "42"]
["03"; "06"; "19"; "31"; "35"; "40"]
["14"; "19"; "22"; "23"; "28"; "43"]
["08"; "12"; "30"; "36"; "41"; "42"]
["04"; "15"; "20"; "24"; "26"; "30"]

Advance

先ほど作ったコードを使いやすくします

こんな感じで使えるようにします

#load @"./mizuho.fsx"
open mizuho.Mizuho

Atari loto6_head |> printfn "%A"

結果

[["1157"; "2017/03/16"; "05"; "17"; "20"; "28"; "39"; "42"];
 ["1156"; "2017/03/13"; "03"; "06"; "19"; "31"; "35"; "40"];
 ["1155"; "2017/03/09"; "14"; "19"; "22"; "23"; "28"; "43"];
 ["1154"; "2017/03/06"; "08"; "12"; "30"; "36"; "41"; "42"];
 ["1153"; "2017/03/02"; "04"; "15"; "20"; "24"; "26"; "30"]]


mizuho.fsxのコードはこちら〜

みずほ銀行のホームページから当選番号を取得するスクリプト · GitHub

mizuho.fsx のちょっとした解説

ちかいうちに書きます・・・

Remove all ads

F#言語を使ってロト6を当ててみる!(心構え編)

F#




LOTO6


Summary

ロト6を当てておいしいお寿司たべたいですっ

というか以前に書いた、R言語を使ってロト6を当ててみる! でロト6を予測するのはcallmekohei的には不可能と思ってたり、、、

でもでもでも、ロト6当てたいのです

というわけで懲りもせずに今度はF#というプログラミング言語を使って予想してみたいとおもいまふ〜

こんな感じで

その1:みずほ銀行のホームページから過去の当選番号を取得する

その2:取得した当選番号をデーターベースSqliteに保存する

その3:データーベースSqliteに保存されてる当選番号をもとに予測する

こんな人にオススメ〜

F#に興味ある人

F#を使ったwebスクレイピングに興味ある人

F#Sqliteを使いたい人

ロト6でおすし食べたい人

コードなど

ここにすべて置いてますっ

github.com

Remove all ads

友達がいないのでパソコンにこんにちはと言ってもらうようにしたった

F#

f:id:callmekohei00:20170318074536p:plain

Summary

callmekoheiと自分の名前を打ち込んだら、こんにちは callmekoheiと返事してもらえるプログラムを作ったった

Motivation

と、友達がいないから・・・(泣

Code

ほとんどが定型コード。コピペでオーケー(^_^)/

/// インタラクティブ・コンソール・アプリの定型パターン
module InteractiveConsole =

    type PrinterAgent() =
        let inbox = MailboxProcessor.Start( fun inbox ->
            let rec loop () = async {
                let! (msg: Choice<string,AsyncReplyChannel<unit>>) = inbox.Receive()
                match msg with
                | Choice1Of2 (s: string) ->
                    System.Console.WriteLine s
                    return! loop ()
                | Choice2Of2 ch ->
                    ch.Reply ()
                }
            loop ()
        )

        member x.WriteLine(s) = inbox.Post (Choice1Of2 s)
        member x.Quit()       = inbox.PostAndReply(fun ch -> Choice2Of2 ch)

    let agent = new PrinterAgent()

    let rec main f str =
        match str with
        | "exit" | "quit" -> agent.Quit()
        | _      -> 
            agent.WriteLine( f str )
            main f ( stdin.ReadLine() )

module ABC =
    
    /// ここに自分のつくったコードを書く!
    let hello (s:string) :string =
        "hello! " + s

    [<EntryPointAttribute>]
    let entry argv =
        try
            InteractiveConsole.main hello ""
            0
        with e ->
            stdout.WriteLine( e.Message )
            0

実行のしかた

// 上のコードをコピペ
$ vim abc.fsx

// コンパイル
$ fsharpc abc.fsx

// 実行
$ mono abc.exe

// 自分の名前を入力する
callmekohei
hello! callmekohei // 返事が返ってくる!

// プログラムを終了する
quit
Remove all ads

(F#) async のメモ

F#

Async<'T>に関してのちょっとしたメモ

0. Prepare

async{...} とすると Async<'T>になる

.

let!とかdo!とかのbang!Asyncをはぎとる。つまりAsync<’T>’Tに、Async<Async<’T>>Async<’T>`になる。

1. RunSynchronously and Start

async blockをバックグラウンドで実行させるかどうかのメソッド .

バックグラウンドで実行させない

// always hello world

async{
    stdout.WriteLine("hello")
}|> Async.RunSynchronously

stdout.WriteLine("world")

バックグラウンドで実行させる

// hello world or world hello or world

async{
    stdout.WriteLine("hello")
}|> Async.Start

stdout.WriteLine("world")

2. Parallel

実行順序は保証されない

// hello world or world hello
let hello1 = async { stdout.WriteLine("hello") }
let world1 = async { stdout.WriteLine("world") }

[hello1;world1]
|> Async.Parallel
|> Async.RunSynchronously

実行順序は保証されないがリストの場所は保証される

// ["hello";"world"]
let hello2 = async { return "hello" }
let world2 = async { return "world" }

[hello2;world2]
|> Async.Parallel
|> Async.RunSynchronously
|> printfn "%A"

3. Order in async block

async blockの中は上から下に実行される

// hello world

let hello = async { do stdout.WriteLine("hello") }
let world = async { do stdout.WriteLine("world") }

async {
    do! hello
    do! world
} |> Async.RunSynchronously

4. Wait async (StartChild)

StartChildを使うことでasync blockの中でAsync<'T>をバックグラウンド処理できるようになる

let wakeUp = async {
    do! Async.Sleep(1500)
    do stdout.WriteLine("Wake up!")
}

let goodMorning = async { stdout.WriteLine("goodMorning") }
let iamSleep    = async { stdout.WriteLine("zzz...") }

async { 
    let! (iamWakeUp:Async<unit>) = Async.StartChild( wakeUp, 100 )
    try
        do! iamWakeUp
    with :? exn ->
        do! iamSleep 
} |> Async.RunSynchronously
// world hello
let hello = async {
    do! Async.Sleep(100)
    do stdout.WriteLine("hello") }

let world = async { do stdout.WriteLine("world") }

async {
    let! child = hello |> Async.StartChild
    do! world
    do! child
} |> Async.RunSynchronously

.

Taskを使った例 .

AwaitIAsyncResultを使うことで待機させることができる

.

無期限に待つ例

let apple  = async { return 100 }
let banana = async { return 70  }
let cherry = async { return 350 }
let sum = [ apple; banana; cherry ]

let eating = async { do stdout.WriteLine("Taste good!") }

async {
    let! (withinMoney:bool) = Async.AwaitIAsyncResult( sum |> Async.Parallel |> Async.StartAsTask)
    do!  eating
} |> Async.RunSynchronously

タイムアウトを指定した例

let wakeUp = async {
    do! Async.Sleep(1500)
    return stdout.WriteLineAsync("Wake up!")
}

let goodMorning = async { stdout.WriteLine("goodMorning") }
let iamSleep = async { stdout.WriteLine("zzz...") }

async {
    let! (wakeUpWithinTime:bool) = Async.AwaitIAsyncResult( wakeUp |> Async.StartAsTask ,100 )
    if    wakeUpWithinTime
    then  do! goodMorning
    else  do! iamSleep
} |> Async.RunSynchronously

5. Exception and Cancel

let green  = fun _ ->  stdout.WriteLine("green") 
let yellow = fun _ ->  stdout.WriteLine("yellow") 
let red    = fun _ ->  stdout.WriteLine("red") 

// 通常の動作
let signalGreen = async { do () }
Async.StartWithContinuations ( signalGreen, green, yellow, red )

// エラー処理
let signalYellow:Async<obj> = async {
    return raise <| new System.Exception()
}
Async.StartWithContinuations ( signalYellow, green, yellow, red )

// キャンセル処理
let signalRed (tokenSource:System.Threading.CancellationTokenSource)  = async {
    do! Async.Sleep(1000)
}

let tokenSource = new System.Threading.CancellationTokenSource()
Async.StartWithContinuations ( signalRed tokenSource , green, yellow, red , tokenSource.Token )
tokenSource.Cancel()
Remove all ads

(F#) Concurrent Queue, Stack and Bag のメモ

F#

ConcurrentQueue

open System.Collections.Concurrent

// ConcurrentQueue クラスは
// thread-safe な queue(FIFO) コレクション
let cq = new ConcurrentQueue<int>()

// Enqueue
[0..9999] |> List.iter cq.Enqueue

// Dequeue
let dequeue = async {
    let mutable subTotal = 0
    while not cq.IsEmpty do
        subTotal <- subTotal + ( cq.TryDequeue() |> snd )
    return subTotal
}

List.init 10 ( fun _ -> dequeue )   // dequeueを10個つくる
|> Async.Parallel                   // パラレルで処理をする
|> Async.StartAsTask                // タスクとして実行
|> fun x -> x.Result                // タスクの結果をとりだす [|13859507; 8933578; 0; 14053043; 0; 0; 13148872; 0; 0; 0|]
|> Array.sum                        // それぞれのタスクの結果を合計する
|> printfn "%A"                     // 結果 49995000


ConcurrentStack

open System.Collections.Concurrent

// ConcurrentStack クラスは
// thread-safe な queue(LIFO) コレクション
let cs = new ConcurrentStack<int>()

// Push
[0..9999] |> List.iter cs.Push

// Pop
let dequeue = async {
    let mutable subTotal = 0
    while not cs.IsEmpty do
        subTotal <- subTotal + ( cs.TryPop() |> snd )
    return subTotal
}

List.init 10 ( fun _ -> dequeue )   // dequeueを10個つくる
|> Async.Parallel                   // パラレルで処理をする
|> Async.StartAsTask                // タスクとして実行
|> fun x -> x.Result                // タスクの結果をとりだす [|13859507; 8933578; 0; 14053043; 0; 0; 13148872; 0; 0; 0|]
|> Array.sum                        // それぞれのタスクの結果を合計する
|> printfn "%A"                     // 結果 49995000


ConcurrentBag

open System.Collections.Concurrent

// ConcurrentBag クラスは
// thread-safe な non-order コレクション
let cb = new ConcurrentBag<int>()

// Add
[0..9999] |> List.iter cb.Add

// Take
let dequeue = async {
    let mutable subTotal = 0
    while not cb.IsEmpty do
        subTotal <- subTotal + ( cb.TryTake() |> snd )
    return subTotal
}

List.init 10 ( fun _ -> dequeue )   // dequeueを10個つくる
|> Async.Parallel                   // パラレルで処理をする
|> Async.StartAsTask                // タスクとして実行
|> fun x -> x.Result                // タスクの結果をとりだす [|13859507; 8933578; 0; 14053043; 0; 0; 13148872; 0; 0; 0|]
|> Array.sum                        // それぞれのタスクの結果を合計する
|> printfn "%A"                     // 結果 49995000
Remove all ads

(F#) throttleを実装してみた!

F#

今コツコツやってるdeoplete-fsharpで、throttleのところでつまづいてるのですが、まぁそれはさておき、面白い記事を見つけたので、やってみました!

matarilloさんというかたがthrottleを自前で実装してたので僕もまねしてF#で実装してみました!

まずはその前にmatarilloさんが作ったC#のコードをF#で使ってみます!

C#のコードをF#でつかう

dll化して取り込めばオーケー

こんな感じ

$ msc -t:library abc.cs

F#のコードは

#r @"./abc.dll"
open WhoToFollowApp
open System
open System.Threading

// 下記のテストコードとおなじ

F#に書き換えてみる

さて,C#のコードを使って感じを掴めたのでF#に書き換えてみます!

こんな感じ

open System
open System.Threading
open System.Threading.Tasks

type Throttle<'T> (millisec:int, action:Action<'T>) =
    
    let mutable signalSequence : int64 = 0L

    member this.Signal (input: 'T) : Async<unit> =
        async { 
            let   id      = Interlocked.Increment( &signalSequence )
            do!   Async.Sleep(millisec)
            let   current = Interlocked.Read( &signalSequence )
            if    current = id
            then  action.Invoke(input)
            else  () 
        }

テストコード

// 500ms値が発行されなかったら最後に発行された値を後続に流す
let throttle = new Throttle<int>(500, fun i -> 
    stdout.WriteLine("{0:HH:mm:ss.fff} {1}", DateTime.Now, i ) )

// 100ms間隔で値を発行
[|1..10|] 
|> Array.iter( fun i ->
    stdout.WriteLine("{0:HH:mm:ss.fff} Signal({1})",DateTime.Now, i)
    throttle.Signal(i) |> Async.Start
    Thread.Sleep(100) )

Thread.Sleep(2000)

stdout.WriteLine("---------------")

// 100ms間隔で値を発行
[|1..5|] 
|> Array.iter( fun i ->
    stdout.WriteLine("{0:HH:mm:ss.fff} Signal({1})",DateTime.Now, i)
    throttle.Signal(i) |> Async.Start
    Thread.Sleep(100) )

Thread.Sleep(2000)

stdout.WriteLine("---------------")

結果

21:27:04.172 Signal(1)
21:27:04.277 Signal(2)
21:27:04.383 Signal(3)
21:27:04.488 Signal(4)
21:27:04.593 Signal(5)
21:27:04.698 Signal(6)
21:27:04.799 Signal(7)
21:27:04.903 Signal(8)
21:27:05.006 Signal(9)
21:27:05.107 Signal(10)
21:27:05.612 10
---------------
21:27:07.218 Signal(1)
21:27:07.323 Signal(2)
21:27:07.429 Signal(3)
21:27:07.534 Signal(4)
21:27:07.639 Signal(5)
21:27:08.140 5
---------------

*** time : 7.727785 s ***

参考

qiita.com

Remove all ads

福岡の美味しいお店〜 ポポット(POPOTE)

Food

最近のcallmekoheiのお気に入りのお店です!

ちょっと飲み屋さんが密集してる場所からは離れてるのですが

すごくいい雰囲気でゆっくり飲めますっ!

福岡に出張などのときは是非!

f:id:callmekohei00:20170228183250p:plain

場所

警固交番の近く

すごく場所はわかりにくいですwww

Remove all ads

インテリセンスを150行で作ってみた!

F#

Summary

F#Compiler Servicesというのを使って

インテリセンス(というか補完)をやってみました!

今回はF#側での補完の話です。Vim側の補完の話はこちらです。

callmekohei00.hatenablog.com

おおまかな動作

辞書(ConcurrentDictionary)に下記をあらかじめキャッシュしておきます。

01. file名
02. Systemのメソッド
03. Collection5のメソッド( Array, Seq, Set, Map, List )
04. Optionのメソッド

コードはこんな感じになります

// 最初にファイル名他を辞書にキャッシュします
if      Seq.isEmpty dic.Keys
then    asyncInit ()   |> Async.RunSynchronously


// もしファイルを変えた場合は
// ファイル名とSystemをキャッシュし直します
// この場合は非同期(Start)で動作します
elif    dic.Item( "filePath" ) <> postData.FilePath
then    asyncReInit () |> Async.Start 


// ドットでの補完かどうかで処理を分けます
if      postData.Line.Contains(".")
then    dotHint ()
else  
        postData.Line.Split(' ')
        |> Array.filter ( fun s -> s <> "" )
        |> fun ary ->
            if    Array.contains "[<" ary  && not ( Array.contains ">]" ary )
            then  attributeHint ( Array.last ary |> fun s -> s.Replace( "[<","" ) )
            else oneWordHint ( Array.last ary )

インテリセンスというか補完のコアになるコード

なぜこう書くのかとかわかりません。

マイクロソフトのホームページに書いてあったからですwww

let private asyncGetDeclarationListInfo ( checker:FSharpChecker) ( ps:PostData ) (arr:(string array * string)) : Async<FSharpDeclarationListInfo> = async {

    let! (projOptions : FSharpProjectOptions) =
        checker.GetProjectOptionsFromScript( ps.FilePath , ps.Source )

    // Perform parsing and type checking 
    let! (parseFileResults : FSharpParseFileResults) , (checkFileAnswer: FSharpCheckFileAnswer) =
        checker.ParseAndCheckFileInProject( ps.FilePath, 0, ps.Source, projOptions )

    let checkFileResults = 
        match checkFileAnswer with
        | FSharpCheckFileAnswer.Succeeded(res) -> res
        | res -> failwithf "Parsing did not finish... (%A)" res

    return! checkFileResults.GetDeclarationListInfo ( Some parseFileResults, int(ps.Row) , int(ps.Col) , ps.Line, (fst arr) |> Array.toList, (snd arr), fun _ -> false )
}

課題

上記のコードasyncGetDeclarationListInfo

いかにリアルタイムで呼び出さないかがポイントになるかと思います。

事前にキャッシュしてない補完項目は通常は気にならないスピードなのですが、

type providerが入ってるコードになると

途端に遅くなります。(2秒から5秒くらい?)

コード

コードは下記に置いてますっ!

こんな感じで作り直したらいいんじゃない?という提案ありましたら

どんな手段でも結構ですので言っていただけると嬉しいです!

github.com

参考のページ

fsharp.github.io

fsharp.github.io

callmekohei00.hatenablog.com

Remove all ads

非同期処理(async)をかじってみた!

F#

Summary

Asyncとはお仕事を管理する方法

お仕事を管理する方法を2つのパターンで考えると理解しやすいかも

お仕事をasync { お仕事 }async { ... }でかこむ

お仕事を人に任せる時は!をつける(let!とかdo!とかreturn!とか)
( ! をつけると async<’T> が ’T となる)

上司部下パターン( Parents - child pattern )

上司の仕事の段取りをもとにお仕事を処理する

こんなかんじ

// 3sec.後にhello0というおしごと
let helloAfter3seconds () = async {
    do! Async.Sleep(3000)
    stdout.WriteLine("hello0")
}

// 上司の仕事の段取り(仕事の段取りは管理者の仕事なので async {} でかこむ)
async {
    
    // 部下に仕事をおねがいする ( ひとに任せるので let! )
    // お仕事の名前は workA とでもしておく
    let! workA = helloAfter3seconds () |> Async.StartChild

    // 上司は上司で自分の仕事をする
    stdout.WriteLine("hello1")

    // 部下にお仕事の進捗状況をたずねる (ひとに任せていたものなので do!)
    // この場合の do は どうだったの? の どう(do)
    do! workA
} 

// 上司の仕事の段取りを実際に行動にうつす
|> Async.RunSynchronously

結果

hello1
hello0

同僚パターン ( flat pattern )

お仕事を手分けして一斉に処理する

// 3sec.後にhello0というおしごと
let helloAfter3seconds () = async {
    do! Async.Sleep(3000)
    stdout.WriteLine("hello0")
}

// hello1というおしごと
let hello1() = async {
  stdout.WriteLine("hello1")
}

// するべきお仕事をリスト化
[ helloAfter3seconds () ; hello1 () ]

// お仕事を各人に割り当てる
|> Async.Parallel

// 一斉にお仕事を処理する
// 早く終わった人から仕事をきりぬける
// 最後の人が終わったらお仕事終了
|> Async.RunSynchronously

結果

hello1
hello0
Remove all ads

ConcurrentDictionaryの使い方

F#

こんな感じ

open System.Collections.Generic
open System.Collections.Concurrent

let dic : ConcurrentDictionary<string,int> = new ConcurrentDictionary< string, int >()

// appleははじめてなので 100
dic.AddOrUpdate("apple",100, fun _ price -> price + 99 )
dic.Values |> printfn "%A" // seq [100]

// appleは2回目のなので 100 + 99
dic.AddOrUpdate("apple",100, fun _ price -> price + 99 )
dic.Values |> printfn "%A" // seq [199]

// appleはすでに登録されているので 199
dic.GetOrAdd("apple",999)
|> printfn "%A" // 199

// bananaははじめてなので 9999
dic.GetOrAdd("banana",9999)
|> printfn "%A" // 9999

// cherryははじめてなので 99999
dic.GetOrAdd( "cherry", fun _ -> 99999)
|> printfn "%A" // 99999


dic.Keys |> printfn "%A"
// seq ["banana"; "cherry"; "apple"]

dic.Values |> printfn "%A"
// seq [9999; 99999; 199]

dic.Item("cherry") |> printfn "%A" // 99999

dic.ContainsKey("apple") |> printfn "%A" // true

dic.Count |> printfn "%A" // 3

dic.ToArray() |> printfn "%A"
// [|[banana, 9999]; [cherry, 99999]; [apple, 199]|]

dic |> printfn "%A"
// seq [[banana, 9999]; [cherry, 99999]; [apple, 199]]

Remove all ads

F#からSQLiteをつかってみる

下記のページに書いてある分でやるとOSXでのFSharpでもSQLite使えました〜

fsprojects.github.io

Summary

FSharp on OSXSQLiteをつかう

下記の3点が必要

System.Data.SQLitenugetする

libSQLite.Interop.dylibコンパイルする

FSharpコード内でDLLImportする

すること

その1

System.Data.SQLitenugetする

その2

libSQLite.Interop.dylibコンパイルする

下記からソースコードをダウンロード

System.Data.SQLite: Downloads Page

List of Release Packages
-> Source Code
-> sqlite-netFx-full-source-1.0.104.0.zip

zipを解凍して

$ cd Setup

$ chmod +x compile-interop-assembly-release.sh

$ bash compile-interop-assembly-release.sh

これでlibSQLite.Interop.dylibができるので

$ chmod -x bin/2013/Release/bin/libSQLite.Interop.dylib

その3

FSharpコード内でDLLImportする

さっきのlibSQLite.Interop.dylibfsxと同じ場所にコピーしてくる

で、コード

#r @"./packages/System.Data.SQLite.Core/lib/net46/System.Data.SQLite.dll"
open System.Data.SQLite
open System.Runtime.InteropServices

module Database =
    
    [<DllImport(@"/Users/kohei/Documents/jikkenSqlite3/libSQLite.Interop.dylib" , CallingConvention = CallingConvention.Cdecl)>] 
    let sqlite_connection : System.Data.SQLite.SQLiteConnection  =
        ( new SQLiteConnection( @"Data Source=:memory:;Version=3;foreign keys=true" ))

    type ABC ( connection : System.Data.SQLite.SQLiteConnection ) =

        let cn = connection

        member theis.sqlite_open : unit =
            cn.Open()

        member this.sqlite_createTable sql  =
            ( new SQLiteCommand(sql, cn)).ExecuteNonQuery() |> ignore

        member this.sqlite_insert  sql =
            ( new SQLiteCommand(sql, cn)).ExecuteNonQuery() |> ignore

        member this.sqlite_select  sql f =
            let reader = ( new SQLiteCommand(sql, cn )).ExecuteReader()
            while ( reader.Read() ) do
               f reader 

module Jikken =
    open Database
            
    let s0 = @"CREATE TABLE IF NOT EXISTS foo ( name VARCHAR(20), price INT )"
    let s1 = @"INSERT INTO foo ( name, price ) VALUES ('apple', 3000 )"
    let s2 = @"SELECT name FROM foo"
    let f = fun (r:SQLiteDataReader) -> 
        [0]
        |> List.fold ( fun acc n -> acc + " " + r.GetString(n) |> fun s -> s.TrimStart() ) ""
        |> stdout.WriteLine

    let db = ABC( sqlite_connection )
    db.sqlite_open
    db.sqlite_createTable s0
    db.sqlite_insert s1
    db.sqlite_select s2 f

実行

fsi ではなく fsc で実行すること

結果

apple

*** time : 0.081165 s ***

追加

libSQLite.Interop.dylibコンパイルするのがめんどくさい人は

下記に置いてますのでgit cloneしてお使いくださいっ

github.com

Remove all ads