2018年12月16日日曜日

curl elixir/concurrent and gorm/gin

http://d.hatena.ne.jp/thata/20100207/1265554365 about Curl command

---------------------------------------------------------------------

https://rei19.hatenablog.com/entry/2015/09/08/093606 elixir lang mix-otpの詳述
大変参考になる

エリクサーは1.6以上では無料電子ブックが公開されている
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
 https://qiita.com/mochizukikotaro/items/b09116e0ad2d30e37098 :: gorm

https://medium.com/@cgrant/developing-a-simple-crud-api-with-go-gin-and-gorm-df87d98e6ed1 :: RESTful-Api Server by gin

package main

import (

"fmt"
"sync"

// "time"
)

func main() {

    type value struct {
mu sync.Mutex
value int
}

var wg sync.WaitGroup
printSum := func(v1, v2 *value) {
  defer wg.Done()

  v1.mu.Lock()
  defer v1.mu.Unlock()

  // time.Sleep(2*time.Second)

  v2.mu.Lock()
  defer v2.mu.Unlock()

  fmt.Printf("sum=%v\n", v1.value + v2.value)
}

var a, b value
wg.Add(2)
go printSum(&a, &b)
go printSum(&b, &a)  // if (&a, &b), no problem
wg.Wait()

} // のところをはずすとデッドロック発生

2018年8月23日木曜日

関数電卓、二分探索(広井を改訂)

//
// calc2.go : 電卓プログラム (変数、組み込み関数の追加)
//
//            Copyright (C) 2014 Makoto Hiroi
//
package main

import (
    "fmt"
    "os"
    "math"
    "text/scanner"
)

// 値
type Value float64

// 構文木の型
type Expr interface {
    Eval() Value
}

// 評価
func (e Value) Eval() Value {
    return e
}

// 単項演算子
type Op1 struct {
    code rune
    expr Expr
}

func newOp1(code rune, e Expr) Expr {
    return &Op1{code, e}
}

func (e *Op1) Eval() Value {
    v := e.expr.Eval()
    if e.code == '-' {
        v = -v
    }
    return v
}

// 二項演算子
type Op2 struct {
    code rune
    left, right Expr
}

func newOp2(code rune, left, right Expr) Expr {
    return &Op2{code, left, right}
}

func (e *Op2) Eval() Value {
    x := e.left.Eval()
    y := e.right.Eval()
    switch e.code {
    case '+': return x + y
    case '-': return x - y
    case '*': return x * y
    case '/': return x / y
    default:
        panic(fmt.Errorf("invalid op code"))
    }
}

// 変数
type Variable string

// 大域的な環境
var globalEnv = make(map[Variable]Value)

// 変数の評価
func (v Variable) Eval() Value {
    val, ok := globalEnv[v]
    if !ok {
        panic(fmt.Errorf("unbound variable: %v", v))
    }
    return val
}

// 代入演算子
type Agn struct {
    name Variable
    expr Expr
}

func newAgn(v Variable, e Expr) *Agn {
    return &Agn{v, e}
}

// 代入演算子の評価
func (a *Agn) Eval() Value {
    val := a.expr.Eval()
    globalEnv[a.name] = val
    return val
}

// 組み込み関数
type Func interface {
    Argc() int
}

type Func1 func(float64) float64

func (f Func1) Argc() int {
    return 1
}

type Func2 func(float64, float64) float64

func (f Func2) Argc() int {
    return 2
}

// 組み込み関数の構文
type App struct {
    fn Func
    xs []Expr
}

func newApp(fn Func, xs []Expr) *App {
    return &App{fn, xs}
}

// 組み込み関数の評価
func (a *App) Eval() Value {
    switch f := a.fn.(type) {
    case Func1:
        x := float64(a.xs[0].Eval())
        return Value(f(x))
    case Func2:
        x := float64(a.xs[0].Eval())
        y := float64(a.xs[1].Eval())
        return Value(f(x, y))
    default:
        panic(fmt.Errorf("function Eval error"))
    }
}

// 組み込み関数の初期化
var funcTable = make(map[string]Func)

func initFunc() {
    funcTable["sqrt"]  = Func1(math.Sqrt)
    funcTable["sin"]   = Func1(math.Sin)
    funcTable["cos"]   = Func1(math.Cos)
    funcTable["tan"]   = Func1(math.Tan)
    funcTable["sinh"]  = Func1(math.Sinh)
    funcTable["cosh"]  = Func1(math.Cosh)
    funcTable["tanh"]  = Func1(math.Tanh)
    funcTable["asin"]  = Func1(math.Asin)
    funcTable["acos"]  = Func1(math.Acos)
    funcTable["atan"]  = Func1(math.Atan)
    funcTable["atan2"] = Func2(math.Atan2)
    funcTable["exp"]   = Func1(math.Exp)
    funcTable["pow"]   = Func2(math.Pow)
    funcTable["log"]   = Func1(math.Log)
    funcTable["log10"] = Func1(math.Log10)
    funcTable["log2"]  = Func1(math.Log2)
}


// 字句解析
type Lex struct {
    scanner.Scanner
    Token rune
}

func (lex *Lex) getToken() {
    lex.Token = lex.Scan()
}

// 引数の取得
func getArgs(lex *Lex) []Expr {
    e := make([]Expr, 0)
    if lex.Token != '(' {
        panic(fmt.Errorf("'(' expected"))
    }
    lex.getToken()
    if lex.Token == ')' {
        lex.getToken()
        return e
    }
    for {
        e = append(e, expression(lex))
        switch lex.Token {
        case ')':
            lex.getToken()
            return e
        case ',':
            lex.getToken()
        default:
            panic(fmt.Errorf("unexpected token in argument list"))
        }
    }
}

// 因子
func factor(lex *Lex) Expr {
    switch lex.Token {
    case '(':
        lex.getToken()
        e := expression(lex)
        if lex.Token != ')' {
            panic(fmt.Errorf("')' expected"))
        }
        lex.getToken()
        return e
    case '+':
        lex.getToken()
        return newOp1('+', factor(lex))
    case '-':
        lex.getToken()
        return newOp1('-', factor(lex))
    case scanner.Int, scanner.Float:
        var n float64
        fmt.Sscan(lex.TokenText(), &n)
        lex.getToken()
        return Value(n)
    case scanner.Ident:
        name := lex.TokenText()
        lex.getToken()
        if name == "quit" {
            panic(name)
        }
        v, ok := funcTable[name]
        if ok {
            xs := getArgs(lex)
            if len(xs) != v.Argc() {
                panic(fmt.Errorf("wrong number of arguments: %v", name))
            }
            return newApp(v, xs)
        } else {
            return Variable(name)
        }
    default:
        panic(fmt.Errorf("unexpected token: %v", lex.TokenText()))
    }
}

// 項
func term(lex *Lex) Expr {
    e := factor(lex)
    for {
        switch lex.Token {
        case '*':
            lex.getToken()
            e = newOp2('*', e, factor(lex))
        case '/':
            lex.getToken()
            e = newOp2('/', e, factor(lex))
        default:
            return e
        }
    }
}

// 式
func expr1(lex *Lex) Expr {
    e := term(lex)
    for {
        switch lex.Token {
        case '+':
            lex.getToken()
            e = newOp2('+', e, term(lex))
        case '-':
            lex.getToken()
            e = newOp2('-', e, term(lex))
        default:
            return e
        }
    }
}

func expression(lex *Lex) Expr {
    e := expr1(lex)
    if lex.Token == '=' {
        v, ok := e.(Variable)
        if ok {
            lex.getToken()
            return newAgn(v, expression(lex))
        } else {
            panic(fmt.Errorf("invalid assign form"))
        }
    }
    return e
}

// 式の入力と評価
func toplevel(lex *Lex) (r bool) {
    r = false
    defer func(){
        err := recover()
        if err != nil {
            mes, ok := err.(string)
            if ok && mes == "quit" {
                r = true
            } else {
                fmt.Fprintln(os.Stderr, err)
                for lex.Token != ';' {
                    lex.getToken()
                }
            }
        }
    }()
    for {
        fmt.Print("Calc> ")
        lex.getToken()
        e := expression(lex)
        if lex.Token != ';' {
            panic(fmt.Errorf("invalid expression"))
        } else {
            fmt.Println(e.Eval())
        }
    }
    return r
}

func main() {
    var lex Lex
    lex.Init(os.Stdin)
    initFunc()
    for {
        if toplevel(&lex) { break }
    }
}
// 二分探索の改正
// 二分探索
def bsearch(x, v, low, high)
  let
    result = 0
  in
    while low <= high and result == 0 do
      let
        mid = (low + high) / 2
      in
        if v[mid] == x then
          begin result = 1,high = -1 end
        else
          if v[mid] < x then
            low = mid + 1
          else
            high = mid - 1
          end
        end
      end
    end,
    result
  end
end

def binarySearch(x, v)
  bsearch(x, v, 0, len(v) - 1)
end

2018年7月7日土曜日

goroutine,nodejs-sqlite3,nodejs-functional,Revel vs ROR

http://nasust.hatenablog.com/entry/2016/11/17/002020 for goroutine
---------------------------------------------------------
http://neos21.hatenablog.com/entry/2018/04/22/080000
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
https://qiita.com/To_BB/items/aa68027a9f319bce7a33
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーhttps://paiza.hatenablog.com/entry/2018/03/23/paizacloud_golang_revel
cf http://railsapps.github.io/installrubyonrails-ubuntu.html RORウブンツ
https://qiita.com/laineek/items/121a9a20d5eb26fb56f4 ROR超入門
------------------------------------------------------------
go/src/myapp/conf/app.conf:

[dev]
db.info = root:@/mydb?charset=utf8&parseTime=True
--------------------------------------
go/src/myapp/app/controllers/gorm.go:

package controllers

import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
    "github.com/revel/revel"
    "myapp/app/models"
    "log"
    )

var DB *gorm.DB

func InitDB() {
    dbInfo, _ := revel.Config.String("db.info")
    db, err := gorm.Open("mysql", dbInfo)
    if err != nil {
        log.Panicf("Failed gorm.Open: %v\n", err)
    }

    db.DB()
    db.AutoMigrate(&models.Post{})
    DB = db
}
---------------------------------------------
go/src/myapp/app/init.go:

package app

import (
  "github.com/revel/revel"
  "myapp/app/controllers"
)

...

func init() {
  ...
  revel.OnAppStart(controllers.InitDB)
}

-------------------------------------------

go/src/myapp/app/models/post.go:

package models

type Post struct {
    Id  uint64 `gorm:"primary_key" json:"id"`
    Body string `sql:"size:255" json:"body"`
}

----------------------------------------------

go/src/myapp/app/models/post.go:

package models

type Post struct {
    Id  uint64 `gorm:"primary_key" json:"id"`
    Body string `sql:"size:255" json:"body"`
}

------------------------------------------

go/src/myapp/conf/routes:

GET     /                                       Post.RedirectToPosts
GET     /posts                                  Post.Index
POST    /posts                                  Post.Create
POST    /posts/:id/delete                       Post.Delete

-----------------------------------------------

go/src/myapp/app/controllers/post.go:

package controllers

import (
    "github.com/revel/revel"
    "myapp/app/models"
    "errors"
)

type Post struct {
    *revel.Controller
}

func (c Post) Index() revel.Result {
    posts := []models.Post{}

    result := DB.Order("id desc").Find(&posts);
    err := result.Error
    if err != nil {
        return c.RenderError(errors.New("Record Not Found"))
    }
    return c.Render(posts)
}
func (c Post) Create() revel.Result {
    post := models.Post{
        Body: c.Params.Form.Get("body"),
    }
    ret := DB.Create(&post)
    if ret.Error != nil {
        return c.RenderError(errors.New("Record Create failure." + ret.Error.Error()))
    }
    return c.Redirect("/posts") 
}
func (c Post) Delete() revel.Result {
    id := c.Params.Route.Get("id")
    posts := []models.Post{}
    ret := DB.Delete(&posts, id)
    if ret.Error != nil {
        return c.RenderError(errors.New("Record Delete failure." + ret.Error.Error()))
    }
    return c.Redirect("/posts") 
}

func (c Post) RedirectToPosts() revel.Result {
    return c.Redirect("/posts") 
}

-------------------------------------------
go/myapp/app/views/Post/index.html:

{{set . "title" "Todo list"}}
{{template "header.html" .}}

<header class="jumbotron" style="background-color:#A9F16C">
  <div class="container">
    <div class="row">
      <h1>Todo list</h1>
      <p></p>
    </div>
  </div>
</header>

<div class="container">
  <div class="row">
    <div class="span6">
      {{template "flash.html" .}}
    </div>
  </div>
</div>

<div class="container">
    <form action="/posts" method="post">
        <div class="form-group">
            <div class="row">
                <label for="todo" class="col-xs-2">Todo</label>
                <input type="text" name="body" class="col-xs-8">
                <div class="col-xs-2">
                    <button type="submit" class="btn btn-success">
                        <i class="fa fa-plus"></i> Add Todo
                    </button>
                </div>         
            </div>
        </div>
    </form>

    <h2>Current Todos</h2>
    <table class="table table-striped todo-table">
        <thead>
            <th>Todos</th><th>&nbsp;</th>
        </thead>

        <tbody>
            {{ range .posts }}
                <tr>
                    <td>
                        <div>{{ .Body }}</div>
                    </td>
                    <td>
                        <form action="/posts/{{.Id}}/delete" method="post">
                            <button class="btn btn-danger">Delete</button>
                        </form>
                    </td>
                </tr>
            {{ end }}
        </tbody>
    </table>
 
</div>


{{template "footer.html" .}}

2018年5月16日水曜日

paizacloud,GolangAnswers, ElixirAnswers,HaskellAnswers

for stack :: curl -sSL https://get.haskellstack.org/ | sh パイザクラウドではディスク不足!

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
for elixir ::


まずapt-getで入れてたelixirを消します
$ apt-get remove elixir
つづいて、適当な場所にelixirのソースコードをcloneしてmake

$ git clone https://github.com/elixir-lang/elixir.git

$ cd elixir

$ git checkout v1.2

$ make clean test

$ sudo make install
---------------------------------------------------------------------------------------

gobook exercises answers ::  https://github.com/torbiak/gopl
go by example japanese :: https://oohira.github.io/gobyexample-jp/hello-world.html
GOの最深部2か所(リフレクションとC言語境界)
リフレクション: https://github.com/torbiak/gopl
C言語境界: https://qiita.com/toshikitsubouchi/items/251f9e69390e1a4260b9
-----------------------------------------------------------------
https://tnomura9.exblog.jp/17526233/  なんだっけ?
elixir book exercises answers ::
https://github.com/laurocaetano/programming-elixir-exercises 
elixir and postgresql ::
elixir-postgres:: https://symfoware.blog.fc2.com/blog-entry-1776.html

mix newでつくったmix.exsにあるdepは重要 消してはいけない
かならずmix deps.getなどしておく!

フェニックス:
Best pages :: https://hexdocs.pm/phoenix/up_and_running.html
For referrable japanese pages :: https://dev.classmethod.jp/server-side/web-application-made-with-elixir-and-phoenix/
--------------------------------------------------------------------------
in ubuntu only (haskell books)

 $ sudo apt-get install sqlite3 これだけではダメ
$ sudo apt-get install libsqlite3-dev これしてないと10章は動かん


2018年5月12日土曜日

phoenix primer, git してGHC並列並行


http://yuji-ueda.hatenadiary.jp/entry/2015/12/21/010620  dockerに構築
https://qiita.com/isaoshimizu/items/9e47a82da9c465fc144a
OSXでのフエニクスだが参考になる
ちなみにhttp://blog1.erp2py.com/2011/05/web2py_17.html うえぶ2ぱい
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
https://qiita.com/sand/items/71d0b35d74a4781f3564   ecto―レジメ
https://qiita.com/sand/items/e98c9e98351b816c7e69  phoenixーレジメ
https://www.casleyconsulting.co.jp/blog/engineer/241/ phoenix intro
https://qiita.com/cohki0305/items/9641cfbe77e3e05e7e8d CRUD by Phoenix
http://ruby-rails.hatenadiary.com/entry/20151011/1444560106
フェニックスのためのセットアップが詳しい 三部作で認証やチャットも勉強できそう
-----------------------------------------
https://qiita.com/satosystems/items/e7fb4295598dc61e4c67

  • 並列処理はかなり有効
  • 並行処理もそこそこ有効(forkIO
  • 並列処理に迫る並行処理もあった(async
処理時間

はじめに

Haskell で処理をマルチコアに分散したい場合どのようにすればよいかをまとめておきます。
負荷のかかる処理としてフィボナッチ数の導出を以下のように行うことにします。
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n - 2) + fib (n - 1)

最適化に関して

まずは fib 関数を普通に一回だけ実行します。
once :: IO ()
once = print $ fib 42
この関数をシングルスレッドで動作させるとおよそ 2.877s かかります。引数の 42 は私の環境で早すぎず遅すぎない適当な値です。
今度は以下の関数をシングルスレッドで動作させてみます。
fourTimes1 :: IO ()
fourTimes1 = do
  print $ fib 42
  print $ fib 42
  print $ fib 42
  print $ fib 42
この実行には 2.879s かかりました。時間がかかるはずの関数を 1 回実行するのも 4 回実行するのもほとんど同じ時間です。この時 fib 関数は愚直に 4 回実行されずに何らかの最適化が働いているようです。
では 4 回 fib 関数を実行するのに以下のように行ってみます。
fourTimes2 :: IO ()
fourTimes2 = mapM_ (print . fib) [42, 42, 42, 42]
この実行には 11.503s かかりました(ほぼ 4 倍の時間です)。fib 42 という形になっていないため最適化が行われないのでしょうか? では同様に mapM_ を使用した以下の関数ならどうでしょうか?
fourTimes3 :: IO ()
fourTimes3 = mapM_ (\_ -> print $ fib 42) [(), (), (), ()]
この関数の実行は 2.862s で終わりました。想定どおりです。どうやら部分適用された関数は最適化されないようです1
以下関数は fib の引数がそれぞれ異なるので(おそらく)最適化が行われず、シングルスレッドで実行に 4.965s かかります。
normal :: IO ()
normal = do
  print $ fib 39
  print $ fib 40
  print $ fib 41
  print $ fib 42
マルチスレッドではどうでしょうか? スレッドを増やした結果は以下のとおりです。
スレッド数時間
-N14.965s
-N24.727s
-N34.702s
-N44.760s
-N54.890s
-N65.074s
-N75.211s
-N85.350s
この関数を逐次処理とし、並行処理と並列処理の比較対象とします。

並行処理(forkIO)

逐次処理でシングルスレッドなら 4.965s かかる処理を forkIO で並行処理にすると、どれぐらいの時間で終わるのでしょうか? 実装は以下のようにしました。
fork :: IO ()
fork = do
  tv <- newTVarIO 0
  _ <- fork' tv $ print $ fib 39
  _ <- fork' tv $ print $ fib 40
  _ <- fork' tv $ print $ fib 41
  _ <- fork' tv $ print $ fib 42
  atomically $ readTVar tv >>= flip unless retry . (== 4)
 where
  fork' :: TVar Int -> IO () -> IO ThreadId
  fork' tv p = forkIO $ p >> atomically (readTVar tv >>= writeTVar tv . succ)
Haskell は forkIO でスレッドを作成できるのですが、残念ながら他の言語の join のようなスレッドの終了を待ち合わせる機能は提供されていません。なので、面倒なのですが、スレッド化したい処理内でスレッドが終わったことをマークする必要があります。今回は TVar Int の値をインクリメントすることですべてのスレッドの終了を待ち合わせています。待ち合わせには retry という関数を使用していますが、TVar の値が変わるまでスレッドがブロックされるので待ち合わせで CPU リソースを消費するということはありません。
さて、この関数の実行時間は以下のとおりです。
スレッド数時間
-N14.919s
-N24.638s
-N33.620s
-N43.049s
-N53.068s
-N63.246s
-N73.347s
-N83.349s
4 スレッドまでは時間短縮し、それ以上になると若干時間延長しています。逐次処理と同じ傾向があります。スレッド起動等のオーバーヘッドでしょうか。今回は forkIO でスレッド化した処理が 4 つだったので、4 あるいは 5 スレッドで並行化するのが最適であり、スレッドが多ければ良い、ということではなさそうです2

並行処理(async)

コメントで async というパッケージを教えてもらいました。今回は以下のように使用しました。
async :: IO ()
async = mapConcurrently_ (print . fib) [39, 40, 41, 42]
なんと並行処理が mapM_ のように一行で記述できてしまいます。実行時間はどうなるでしょうか?
スレッド数時間
-N14.858s
-N22.848s
-N32.833s
-N42.123s
-N52.207s
-N62.440s
-N72.481s
-N82.574s
効率に関しても forkIO よりもかなり良いです。パッケージの実装を見ると、単に forkIO をラップしているわけではなさそうです。今回のケースで言えば、forkIO を使う理由が見当たりません。

並行処理(lifted-async

async は並行処理が IO に依存しているため、他のモナド内で使用するには使い勝手が悪い場合がありますが、lifted-async を使用すれば様々なモナド内で並行処理が行えます。
lasync :: IO ()
lasync = mapConcurrently (\a -> return $ fib a) [39, 40, 41, 42] >>= mapM_ print
上記コードは IO モナド内で実行しているためわかりづらいですが、mapConcurrently に渡しているラムダから print が消えており、任意のモナドが使用できることがわかります。
スレッド数時間
-N14.912
-N24.697
-N34.716
-N44.695
-N54.881
-N65.129
-N75.359
-N85.46
時間を計測してみたところ、冒頭のグラフでも見て取れるように、逐次処理と同じパフォーマンスしか出ていません3

並列処理

並列処理ならどうなるでしょうか?
eval :: IO ()
eval = do
  let as = parMap rpar fib [39, 40, 41, 42]
  mapM_ print as
並行処理と比べ並列処理はかなり簡潔に記述できます。特に純粋な関数を純粋なまま並列化できるのが美しいです。この関数の実行時間は以下のとおりです。
スレッド数時間
-N14.978s
-N22.857s
-N32.559s
-N42.103s
-N52.186s
-N62.281s
-N72.383s
-N82.386s
かなり効率よく処理が行えているようです。-N4 を指定した処理時間が記事冒頭の once という関数一回の処理時間(2.877s)より短いのは、冒頭の処理は -N1 を指定しているからであり、-N4 を指定すると 2.105s になります。つまりこの並行処理は最も計算時間のかかる fib 42 を行っている間に fib 39fib 40fib 41 の計算は他の CPU コアを使用して終わっている、ということを意味し、また並列化のオーバーヘッドがほとんどない、ということも表しています。

まとめ

シングルスレッドで処理した場合、逐次処理、並行処理、並列処理はどれもほぼ同じ時間がかかります。スレッド数を増やすと並行処理、並列処理はその恩恵が得られ、特に並列処理のそれは顕著です。
処理時間
Haskell(GHC)では、複数スレッドを用いると自動的に複数のコアが使用されます4forkIO を用いた並行処理でもスレッド数に応じたマルチコアが利用されているようではありますが、その効率は rpar を用いた並行処理には及びません。ただし async パッケージを使用した並行処理であれば、rpar とほぼ同等の効率を得られることもわかりました。
関数型言語と並行・並列処理は相性がよく、今回も実際目的の関数だけをかんたんに並行化・並列化することができました。うまく活用してマシンリソースを効率よく使用していきましょう。
なお、今回使用したソースコードは以下に置いてあります。
-----------------------------------------------------------------------------------

mkdir mc
cd mc
git clone https://github.com/satosystems/mc
cd mc
stack build and thereafter....
$ stack exec mc -- normal +RTS -s -N4
$ stack exec mc -- fork +RTS -s -N4
$ stack exec mc -- async +RTS -s -N4
$ stack exec mc -- lasync +RTS -s -N4
$ stack exec mc -- eval +RTS -s -N4