Quantcast
Channel: 初心者タグが付けられた新着記事 - Qiita
Viewing all 21607 articles
Browse latest View live

c++でキャッシュアルゴリズム(fifo lfu)

$
0
0

初めに

初めましてえれです。

修士の時ネットのワークのキャッシングについて研究していました。その際に意外とキャッシュアルゴリズムの記事が少なかったため備忘録もかねて書いていきたいと思います。

注意点として今回はvectorを使用していますが、
c++でキャッシュアルゴリズムを実装する上で使用するSTDのライブラリでLISTを使うかVECTORを使うかは自分が実現したい仕組みに即したものを選択してください。
vectorにもlistにもそれぞれ利点と欠点があります。
特に学術分野のシミュレーションで使用するのであれば演算速度が重視されるかと思うのでプログラム設計はしっかりとやってからプログラムしましょう。


コンパイラをインストールするのが面倒な方はこちらがおすすめです。
paiza.IO

stdを使用する際はリファレンスを読みましょう
stdのリファレンス


FIFO

まずは先入れ先出しのキャッシングアルゴリズムであるFIFO(First In, First Out)です。
こちらの動作は簡単でデータを入れていきキャッシュ(またはバッファ)などからあふれた場合に古いデータから削除していくアルゴリズムです。

プログラムとしてはint型のデータが100個入る配列を作り、vectorでキャッシュ(またはバッファ)を作成します。
intの配列はfor文でもよかったのですが、lfuを見越して別に作成しました。


#プログラム解説

キャッシュ容量は5としているので、下記の部分ではキャッシュ容量が溜まるまでを書いています。
出力部分が多いのでわかりずらいですが、大切な部分はv1.emplace_back(nu[i]);くらいです。

部分.cpp
 if(v1.size() <= 4){
        v1.emplace_back(nu[i]);
        cout << "==" << i+1 << "回目 ==" << endl;    
        for(auto a :v1){cout << a << " ";}
        cout << endl;
     }

次にキャッシュ容量が満タンになった状態で新しい数字がキャッシュに入る場合の動作を書いています。
vectorにはlistのようなpop_frontの関数がないのでeraseで配列の先頭(begin)を削除し値を挿入する。
この場合、vectorは可変長のため挿入してから削除してもよいが、実際に実現したい動きとは違ってしまうため削除→挿入の順にしている。

部分.cpp
 else if(v1.size() == 5){
        cout << "==" << i+1 << "回目 ==" << endl;
        cout << "削除された値:" << v1.front() << endl; 
        v1.erase(v1.begin());
        v1.emplace_back(nu[i]);
        for(auto a :v1){cout << a  << " ";}
        cout << endl;
      }

以下全文

mein.cpp
#include <iostream>
#include <cassert>
#include <vector>
using namespace std;
int main(void){

    vector<int> v1;

    int nu[100];
    int i;

    for (i = 0; i < 100; i++ ) {
        nu[i] = i;
    }

    //配列nuに0から99の数字が挿入された
    //今回の配列サイズは5
    for (i = 0; i < 100; i++ ) {
     if(v1.size() <= 4){
        v1.emplace_back(nu[i]);
        cout << "==" << i+1 << "回目 ==" << endl;    
        for(auto a :v1){cout << a << " ";}
        cout << endl;
     }else if(v1.size() == 5){
        cout << "==" << i+1 << "回目 ==" << endl;
        cout << "削除された値:" << v1.front() << endl; 
        v1.erase(v1.begin());
        v1.emplace_back(nu[i]);
        for(auto a :v1){cout << a  << " ";}
        cout << endl;
      }
    }  
}

LRU

次に参照された回数でキャッシュ内を入れ替えるLFUを紹介する。
先にも書いた通りこのアルゴリズムはキャッシュ内のデータが参照された回数をカウントしておき
その回数でキャッシュ内を入れ替える。

今回は2度目の挿入が行われた場合に順番を入れ替え、実際に配列の中身のカウントを行うことはせず入れ替えるのみとしている。
動きの一例としては
[古→  新]
[1 2 3 4 5]

3が来た場合、3を削除し
[1 2 4 5]

3を入れなおす
[古→  新]
[1 2 4 5 3]
この動作を繰り返すことでLFUを実現している。

また、ランダム関数を使うことでランダムな数字が配列に格納されていく。
そうすることで、上記の動きを再現できるような環境としている。

main.cpp
#include <iostream>
#include <cassert>
#include <vector>
using namespace std;
int main(void){

    vector<int> v1;
    int nu[100];

    int s;
    srand(time(NULL));

    for(int i = 0; i <100; i++){
        s = rand() % 10;
        nu[i] = s;
    }

    for(int i = 0; i <100; i++){

    if(v1.size() <= 4){
        v1.emplace_back(nu[i]);
        cout << "==" << i+1 << "回目" << ":来た数字:" << nu[i] << "==" << endl; 
        cout << "古      新" << endl;
        for(auto a :v1){cout << a << " ";}
        cout << endl;
    }else if(v1.size() == 5){

    for(auto it = v1.begin(); it != v1.end(); it++){
    if(*it == nu[i]){
    cout << "==" << i+1 << "回目" << ":来た数字:" << nu[i] << "==" << endl;
    cout<<"入れ替えました:" << *it << endl;
    cout << "古      新" << endl;
    v1.emplace_back(nu[i]);
    v1.erase(it);
    for(auto a :v1){cout << a  << " ";}
    cout << endl;
    break;
    }
    continue;
    }

    cout << "==" << i+1 << "回目" << ":来た数字:" << nu[i] << "==" << endl;
    cout << "削除された値:" << v1.front() << endl; 
    cout << "古      新" << endl;
    v1.erase(v1.begin());
    v1.emplace_back(nu[i]);
    for(auto a :v1){cout << a  << " ";}
    cout << endl;
    } 
    }
}


最後に

最後までお読みいただきありがとうございました。
私自身の研鑽につながるため、ご指摘や修正案などお気軽にコメントをお願い致します。

出力のコメントの多いプログラムとなってしまいましたが、アルゴリズム系は机上でやっていると頭が混乱し
振出しに戻ってしまうことが多々ありました。
そのため、自分の見やすい出力で注釈をつけることはとても大切なことだと感じています。

プログラムになれていくるとGDBなどのデバックツールを使うため、こういったコメントはつけなってきます。

今後

実際に配列の中身をカウントし都度入れ替えるLFUや最後に参照された時間でキャッシュを入れ替えるLRUなどを実装してみたいと考えている。


脱jQueryを目指してajaxメソッドをaxiosに置き換える

$
0
0

脱jQueryを目指してajaxメソッドをaxiosに置き換えます。

準備

axiosを使うために以下のサイトからjsファイルをダウンロードして読み込んでおきます。

https://github.com/axios/axios

<script src="axios.min.js"></script>

GET通信

// jQuery
$.ajax({
  type: 'GET',
  url: 'http://localhost/test',
  params: { name: 'Taroimo' },
}).then(...);

// axios (1)
axios.get(
  'http://localhost/test',
  { name: 'Taroimo' }
).then(...);

// axios (2)
axios({
  method: 'GET',
  url: 'http://localhost/test',
  params: { name: 'Taroimo' }
}).then(...);

POST通信

// jQuery
$.ajax({
  type: 'POST',
  url: 'http://localhost/test',
  data: { name: 'Taroimo' },
}).then(...);
// axios (1)
axios.post(
  'http://localhost/test',
  { name: 'Taroimo' }
).then(...);
// axios (2)
axios({
  method: 'POST',
  url: 'http://localhost/test',
  data: { name: 'Taroimo' }
}).then(...);

Swift基礎文法

$
0
0

Swift基礎文法

Swiftの初学者向けの内容です。
忘備録的な意味で基本的な構文を残しておきます。

コメント

単数行

// コメント

複数行

/* コメント
コメント
ここまでコメント*/ 

print文

Playgroundのデバッグエリアに文字出力する。

print("デバッグに出力") // 文字列をそのまま出力する
print(hoge) // 変数の内容を出力する

変数

再代入可能な変数を宣言・初期化する。

var hoge: Int = 0

宣言の型は省略できる。

var hoge = 0 

定数

イミュータブル(変更不可)な定数を扱う。
再代入しようとするとエラーになるため、意図しない代入を防げる。

let foo = "boo"
foo = "test" // 再代入すると構文エラー。

データ型

代表的なデータ型。
浮動小数の演算はパフォーマンスを食うため、型の検討は慎重に。

扱う値 とりうる値
Int 符号付き整数 ※64bitまで
UInt 符号無し整数 ※64bitまで
Float 小数 32bitまで
Double 小数 ※64bitまで
Bool 真偽 true, またはfalse

※64bitまで値が取れるのは iPhone 5s以降 のみ
それ以前の環境ではInt64を指定しても32bitまでしか扱えない。

let val1: Int = 10
let val2: Float = 0.5
let val3: Double = 10.5
let val4: Bool = true

型を省略すると 値に適した型で格納される。

let val1 = 10  // 整数
let val2 = 0.5 // 浮動小数
let val3 = true // 真偽

整数と浮動小数の計算

型を合わせてから計算する。

var value1 = 10
var value2 = 5.5
var sum = Double(value1) + value2 // 15.5

ただし、小数から整数に変換すると小数部分が 切り捨て される。

var value1 = 10
var value2 = 5.5
var sum = value1 + Int(value2) // 10

文字列の計算

文字列同士は + で結合できる。

let str1 = "君の"
let str2 = "名は。"
print(str1 + str2) // 君の名は。

文字列以外の結合は String に変換してから行う。

let str1 = "秒速"
let str2 = "センチメートル"
var speed = 5
print(str1 + String(speed) + str2) // 秒速5センチメートル

変数の場合は \(変数名) 記法で文字列変換できる。
読みやすさを考慮して使おう。

var speed = 5
print("秒速\(speed)センチメートル") // 秒速5センチメートル

配列

複数の値を保持できる。

配列の宣言

letで宣言すると内容を後から変更できなくなる。

var array1: [Int] = [1, 3, 5, 7, 9]
let array2: [Int] = [2, 4, 6, 8, 10]

型は省略できる。

var array1 = [1, 3] 

宣言のみで初期化しない場合は [型]() と記す。

var array: [String] = [String]() // 空のString配列が出来る

型は省略できる。

var array = [String]() // 空のString配列が出来る

型違いの値は格納できない。
型違いの値を許容したい場合は Any 型で宣言する(取り出し時にダウンキャストする)。

var array1 = [0, "a"] // エラーになる
var array2: [Any] = [5, "a"]
print(array2[0]) // 5
print(array2[1]) // a

配列の利用

アクセスは 添字(要素番号)で行う。

var numbers = [1, 3, 5]
print(numbers[0]) // 1

値の追加は append()

var numbers = [1, 3, 5]
numbers.append(7) //[1, 3, 5, 7]

値の削除は remove(at: 添字)

var numbers = [1, 3, 5]
numbers.remove(at: 2) // [1, 3]

辞書

key-value方式で値を複数保持できる。

辞書の宣言

辞書を宣言する。
let で宣言した辞書は後から追加・変更ができない。

var scores1: [String:Int] = [String:Int]() // 空の辞書を作成する。
var scores2 = [String:Int]() // 宣言部の型は省略可能。
var scores3 = ["Test1":80, "Test2": 60] // 宣言と同時に代入することも出来る。

辞書に追加する

辞書に要素を追加する。

var scores = [String:Int]()
scores["Test1"] = 80

辞書を利用する

変数名[key] と記すと対応する value にアクセスできる。

var scores1 = ["Test1":80, "Test2": 60]
print(scores1["Test1"]) // 80
scores1["Test2"] = 50 
print(scores1["Test2"]) // 50
let scores2 = ["Test1":80, "Test2": 60]
scores2["Test2"] = 50 // 定数に再代入するとエラーになる。

key に対応する value が無い場合は nil が返る。
要素の削除は nil の代入で行う。

var scores = ["Test1":80, "Test2": 60]
print("Test3") // nil
socres["Test2"] = nil
print("Test2") // nil

nilとOptional型

Swiftでは「何もない」ことを表現するために nil を使う。
nilを変数に格納するためには Optional型 で宣言した変数に代入する必要がある。
Optional型の変数は 型? 記法で宣言する。

var str1: String? = "hello" // オプショナル<String型>に文字列を代入
print(str1) // Optional("hello") が出力される。(ラップされた状態で出力される)
var str2: String? = nil
print(str2) // nil が出力される。

Optional型のアンラップ

Optional型でラップされた値は ! で取り出すことができる。
ただし、nilが代入されている変数を直接アンラップするとエラーになる。

var str1: String? = "hello"
print(str1!) // "hello"が出力される
var str2: String? = nil
print(str2!) // エラーになる

if let構文でnilチェックする

Optional型の変数に nil のどちらが入っているか事前に知りたい場合は if let構文 を使う。

var value: String? = "hello"
if let value = value {
  print(value) // アンラップされた "hello" が出力される
}

if let 構文では、上記のように元の変数名 value と同名の変数名を使うことができる。
スコープ内ではアンラップされた変数が優先して使われる。

アンラップ後の変数を使わない場合は、下記のようにif let 構文内で変数名を省略することができる。
省略する場合は _ (アンダースコア) を用いる。

var value: String? = "hello"
if let _ = value {
  // value が nil でない場合の処理
}

【補足】型? がよく分からない

Optionalが初見だとなぜコンパイルエラーになるか分からないと思う。

var value1: Int? = 10
var value2 = value1 * value1 // コンパイルエラーになる

型?Optional<型> と同義である。

var value1: Int? = 10
var value2: Optional<Int> = 10 

Int?nilが入るかもしれない型 ではなく、Optional<Int> というIntとは別の型
だから最初のような操作はエラーになる。

var value1: Int? = 10
var value2 = value1 * value1 // Optionalそのままでは掛け算はできず、エラーになる

! は Optional型という箱から値を取り出す、と分かれば理解も深まると思う。

var value1: Int? = 10
var value2 = value1! * value1! // 100

! の省略

宣言時に ? の代わりに ! を使うと、Optionalから取り出す度に ! を記す必要がなくなる。

var value1: Int! = 10
var value2 = value1 * value1 // 100

感想

これまで 連想配列 と呼んでたものを 辞書 という呼び名で呼ぶことにモダンっぽさを感じる。
Optional型は頻出なので是非おさえよう。

Railsチュートリアル 第7章 ユーザー登録 - プロのデプロイ

$
0
0

前提条件

これまで何度か本番環境へのデプロイを行ってきました。しかしながら、「RDBMSへのアクセスが発生するアプリケーションの本番環境へのデプロイ」は、今回が初めてです。「RDBMSにアクセスする」となると、本番環境へのデプロイにも、これまでとは違うレベルの配慮が求められることになります。

本番環境でのSSL

SSLの必要性

Railsチュートリアル第7章、今回開発したユーザー登録フォームで本番環境にデータを送信すると、名前やメールアドレス、パスワードといったデータがネットワーク越しに流れていきます。これらの通信内容は、途中で捕捉することが可能です。しかもデフォルトでは通信内容が暗号化されていません。「暗号化されていない通信内容を途中で捕捉できる」というのは、例えば名前やメールアドレスといった情報を容易に盗むことができてしまうということです。

というわけで、ネットワーク上を流れていく情報の安全を確保するため、「クライアントとサーバーの間で通信内容を暗号化する」という技術を導入する必要が出てきます。SSLというのは、そうした技術の中でも主流となっている技術です。HTTPの通信に対してSSLを適用したものは、特にHTTPSと呼ばれます。

とりわけ昨今では、「不特定多数のユーザーが使用する前提のもと、利便性を優先してあえて通信の暗号化を行わない」という公衆無線LANが世界各所で運用されるようになっています。そうした環境が当たり前に存在することを前提とするならば、「実際に使用する通信経路に関係なく、クライアントとサーバーの間で通信内容を暗号化する」という技術、例えばSSLの必要性は非常に高いものとなります。

RailsとSSL

今回SSLを実装するのは、まずユーザー登録ページのみが対象です。しかしながら、Railsにおいては、Webサイト全体に対してSSLを適用することも容易に可能なようになっています。例えば、「ログイン機構をセキュアにする」「セッションハイジャックの脆弱性に対処する」といった目的に対しても、「SSLの採用」という解決を容易に実現することができるのです。

SSLの有効化も容易に可能です。config/environments/production.rbという、本番環境に適用する設定を記述するRubyコードを1行変更するだけです。この設定により、SSLが有効になるだけではなく、ユーザーに対してSSLの使用を強制するようにもなります。

config/environments/production.rb
  Rails.application.configure do
    ...略
    # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
-   # config.force_ssl = true
+   config.force_ssl = true
    ...略
  end

HerokuにおけるSSL

Herokuでは、デフォルトの状態でSSLを使用することが可能です。しかしながら、SSLの使用をWebブラウザに強制することはしていません。例えば、現時点で本番環境上にデプロイされているRailsチュートリアルのサンプルアプリケーション(第6章終了時点のもののはずです)のURLのうち、https://http://に変えても、サンプルアプリケーションのWebサイトにアクセスすることができてしまいます。

httpsスキームではなくhttpスキームでWebサイトにアクセスすると、その通信は安全ではなくなってしまいます。

Heroku上のRailsアプリケーションにおいて、ユーザーに対してSSLの使用を強制させるには、上述「RailsとSSL」項に記載の通り、Rails側で所定の設定を行う必要があります。

SSLそのもののセットアップ

SSLそのもののセットアップには、本来、「ドメイン毎にSSL証明書を購入し、その他多くの作業を行う」必要があります。しかしながら、Herokuにおいては、Herokuのサブドメインを用いるのであれば、Heroku側でセットアップされたSSL環境を使用することが可能です。この場合、SSL証明書もHeroku側が用意しています。

一方、独自サブドメインを使用する場合は、SSL証明書を購入し、「購入した証明書をHerokuにセットアップする」という作業が必要となります。

本番環境用のWebサーバー

Railsチュートリアルでは「Webサーバー」という見出しになっていますが、Webサーバーというよりは、アプリケーションサーバーに関する話です。

WEBrickとPuma

Herokuのデフォルトでは、WEBrickというアプリケーションサーバープログラムを使用する設定になっています。WEBrickは環境設定や実装が容易である反面、著しく大量のトラフィックを扱うには不向きな実装となっています。すなわち、WEBrickは本番環境のサーバープログラムとしては不適切であるということです。

そこで、より本番環境向きのアプリケーションサーバープログラムであるPumaを使用するようにHerokuをセットアップする必要があります。必要なプロセスとしては以下のとおりです。

  1. puma gemをGemfileに追加する
  2. Heroku上でPumaプロセスを実行するために、Procfileという設定ファイルを追加する

上述手順の注意点は以下です。

  • Rails 5では、デフォルト設定でPumaが使用可能である
  • Procfileは、Railsアプリケーションのルートディレクトリ(Gemfileがあるのと同じディレクトリ)に置いておく必要がある

Procfileの内容は以下の通りになります。

web: bundle exec puma -C config/puma.rb

余談 - PHPにおけるアプリケーションサーバー

ちなみに、Webアプリケーションの開発言語がPHPである場合、Webサーバープログラムとアプリケーションサーバープログラムを別にセットアップするのは一般的ではありません。PHP環境においては、ApacheしかりNginxしかり、「WebサーバープログラムにPHPのアプリケーションサーバー機能が実装されている」というのが一般的であるからです。

本番環境へのデプロイ

実際のデプロイ操作

まずは開発環境にて、rails testが通ることを確認します。

(開発環境)
# rails test
Running via Spring preloader in process 352
Started with run options --seed 32564

  21/21: [=================================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.41443s
21 tests, 50 assertions, 0 failures, 0 errors, 0 skips

テストが通ることが確認できたら、ソースコードがある環境から次の手順を実行します。

(ソース環境)
>>> git add -A
>>> git commit -m "Use SSL and the Puma webserver in production"
>>> git push
>>> git push heroku
>>> heroku run rails db:migrate

ここでは、以下の手順を実施しています。

  1. Git…ここまでの変更をステージング
  2. Git…コミットメッセージを付けた上でコミット
  3. Git…GitHubリポジトリにプッシュ
  4. Git…Herokuにデプロイ
  5. Heroku…データベースのマイグレーション処理

演習 - プロのデプロイ

1. ブラウザから本番環境 (Heroku) にアクセスし、SSLの鍵マークがかかっているか、URLがhttpsになっているかどうかを確認してみましょう。

スクリーンショット 2019-10-25 19.37.03.png

サンプルアプリケーションのトップページが無事表示されました。URLの前に緑色の鍵マークが表示されています。URLもきちんとhttps://から始まっています。

2. 本番環境でユーザーを作成してみましょう。Gravatarの画像は正しく表示されているでしょうか?

「Sign up now!」というボタンをクリックしてみます。

スクリーンショット 2019-10-25 19.38.35.png

ユーザー登録フォームが表示されました。

スクリーンショット 2019-10-25 19.42.10.png

ユーザー登録も無事完了しました!Grabatarの画像もきちんと表示されています。

WPF 新しい項目の追加でウィンドウ(WPF)がない時の対処法

$
0
0

wpf 新しい項目の追加でウィンドウ(WPF)がない時の対処法

WPFをC#のアウトプットとして勉強していますが、この新しい項目の追加でウィンドウ(WPF)がなくて結構時間食ったので、それに関して書いておきます。

wpf.PNG

今はWPFの項目がありますが、前は、なかったです。

結論

1.windowsのスタートメニューからvisual studio installerを検索

2. visual studio installerを起動

これの変更のボタンを押して変更画面へといく
wpf02.PNG

3. 変更画面から,NETデスクトップアプリ開発をダウンロードするといける

wpf03.PNG

閲覧ありがとうございました。
また、自分が困ったことを投稿できるように頑張ります。
なにか不憫な点がございましたら、コメント欄にてコメントをいただければ幸いです。

Railsでポートフォリオを作ってみよう! vol.1 前編 (Docker導入編)

$
0
0

※すぐにDockerの導入から始めたい人は→Dockerの導入

Dockerとは

DockerとはDocker社が、開発を行っている。
コンテナ型の仮想環境を作成、配布、実行をすることができるプラットホームのこと。
公式文章
日本語訳公式文章

ホストマシンのカーネルを使用し、プロセス等を隔離しつつ実行を行っている為、別のマシンを動かしているように使用する事ができる上に、軽量、高速で起動や停止を行う事ができる。
比較対象としてよく仮想マシンが挙げられている事が多いが、違いとしては、

仮想マシン
物理マシン > ホストOS > Hypervisor > ゲスト(仮想)OS > ミドルウェア > アプリ

コンテナ
物理マシン > ホストOS > DockerEngine >ミドルウェア > アプリ

である。

参考文章
Hypervisorとは?
ミドルウェアとは?

コンテナの利点

・コード化されたファイルを共有することにより、どこの誰でもどのようなOSでも同じ環境が作成可能
・構築と削除が簡単に行える
・作成した環境の配布のしやすさ

つまりはめっちゃ万能

Dockerの導入

Dockerの導入方法は複数ある(公式サイトからのDLやyarm経由での導入)
今回はHomebrew経由で導入を行ったが、まずHomebrew持ってないよ!っていう人もいると思うので、導入から。
まず、Dockerをインストールするまでに前提条件で必要になってくるのは
・Homebrew
・homebrew-cask
の2つなのでそれらを引っ張ってくる

>>Homebrewの導入
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

>>caskの導入
$ brew update
$ brew install caskroom/cask/brew-cask

そして上2つを入れれたら次にDockerを入れる

>>Dockerの導入
brew cask install docker

以上。おしまい。
※結構導入には時間がかかる為、時間に余裕があるときに行いましょう。

Dockerを起動してみる

Dockerの導入は完了したので、早速Dockerを試してみたいが、このままdockerコマンドを打ち込んでも [command not found] と出てしまい何もする事ができない。
理由としてはDockerの起動を行っていないからなので

$ open /Applications/Docker.app

を叩くとDockerから
Docker Desktop is now up and running!
と言われ、dockerコマンドの使用が可能になる。

$ docker --version
Docker version 19.03.3

今回はDockerの導入〜起動までを行ってきた。
次回docker-composeの導入〜起動までを行い、rails環境を構築してみたいと思う。

UE4で家族を錬金する。 4日目

$
0
0

UE4で彼女ができるなら、、
家族も錬金すればいいじゃない、、
その過程を記録していきたいとおもいます。

目標としてUe4のアセットである
Paragonのみなさんを家族になってもらおうと思います。

1.前日のふりかえり

おかあさん役に「Paragon:Phase」さんをダウンロード
image.png

アニメーションテスト→FX→サウンド
見るべきポイントがだいぶ早くなってきた感じ。
Qiitaにもなれてきたぞ!
ひとまず全部のキャラクターを家族化し
家族的な実装?もほどこしたい。

2.長女の選定

1姫2太郎がよいかなとおもい。
長女役として「Paragon:Muriel」さんをダウンロード

0001.JPG

アセットのサイズは0.7GBほど、軽めな感じ。

https://www.youtube.com/watch?v=h4eBdXcj_lk

ダウンロード中にどんなキャラクターなのか研究
ロボットの天使でおお!。。。といった感じ
くるくる回りながら飛翔していく感じが
とても優雅でかっこいいムーブ

3.アニメーションと跳んで家族

家族みんなでUltimate_Startモーションこれは
ジャンプの新定番になるかも!

0.jpg

ちなみに攻撃モーションはほぼない様子で防御系の
キャラみたいです。

4.あかちゃんがうまれたら追加するアセット

1.jpg

Anim_Hold_Babyのアニメーションがめっちゃイケてる。

0.jpg

はい!おぎゃぁ!

PHPキャッチアップ~ToDoリスト作成~

$
0
0

なんでわざわざ公開したの?

PHPを触りくらい使えるようにとキャッチアップ中だからです。
とりあえずアウトプットして皆様のご意見を戴かないと、自己研鑽できないからです。
お決まりのToDoリストくらいは作れるぜってアピールしたいからです。

PHPらしいコードってのがイマイチ理解できていないので、有識者様、どうか私奴に教えてください。

コード

ToDo.php
<?php
    $pdo =  new PDO('mysql:dbname=php;host=localhost','root','');

    if(isset($_POST['submit'])){
        $content = $_POST['content_name'];

        $sql = "INSERT INTO doing (content) VALUES ('$content')";
        $insert = $pdo->query($sql);
    }


    $sql = 'SELECT content FROM doing';
    $results = $pdo->query($sql);
?>

<html>
    <head>
        <meta charset="UTF-8">
        <Title>ToDoリスト</Title>
    </head>
    <body>
        <h1>ToDoリスト</h1>
        <form action="ToDo.php" method="post">
            <ul>
                <li><span>タスク名</span><input type="text" name="content_name">
                <span><input type="submit" name="submit"></span></li>
            </ul>
        <ul>
        <ul>
            <?php 
                foreach($results as $result){
                    echo "<li>";
                    echo $result['content'];
                    echo "</li>";
                };
            ?>
        </ul>
        </ul>
    </body>
</html>

DBは下記の通り作成しました

doing.sql
CREATE DATABASE php;

CREATE TABLE doing (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    content VARCHAR(100) NOT NULL
);

[翻訳] Remove Richard Stallman

$
0
0

この記事は Salam G. 氏による Remove Richard Stallman という記事の和訳です。
やや旧聞になりますが、ストールマン氏が MIT を辞職しました。その大きなきっかけとなったのが Salam G. 氏によるこの記事です。私がこの記事を和訳するのは、日本の IT に携わる多くの人に、IT や学問の世界におけるジェンダーの問題について関心を持って欲しいと願うからです。これは工学・自然科学・社会科学・人文学・工学に携わるすべての人々に関係があることだと、私は信じています。

  • 翻訳した部分は本文のみに留め、原文の補遺と編集記録は省いてあります。
  • この記事は児童虐待や性暴力に関する話題を含みますので注意してください。
  • 「ポエム」タグは適当なタグが見当たらなかったので使いました。

以下本文。


腹が立って仕事にならないのでこれを書いている。

私がこれを書いているのは、2019年9月11日水曜日午前11時、MIT Computer Science and Artificial Intelligence Laboratory (CSAIL) のメーリングリストに投稿されたとあるメールが、友人から転送されてきたからである。

元のメールの差出人はリチャード・ストールマン。著名な計算機科学者である。

元のメールでは、とある女子学生が、この Facebook イベントについて書いたメールへの、ストールマンによる返答がなされていた。そのイベントというのは、ジェフリー・エプスタインの寄付についての抗議に参加するよう、MIT の学生らが呼びかける、というものである。

金曜日のイベントの告知はマーヴィン・ミンスキーに対する不正義である:

「(エピスタインの件の犠牲者のひとりを暴行したかどで糾弾されている)AI の『パイオニア』たる故人マーヴィン・ミンスキー」〔という箇所のことである〕

不正義というのは「暴行」という語のことである。「性的暴行」という言葉は曖昧で、糾弾の拡大を促進するものである。
すなわち、ある人がXをしたと主張して、人々がそれはXよりももっと悪いYであると思うように誘導しているのである。

上で引用した糾弾の文言はその拡大の明らかな例である。参照した文書は、ミンスキーがエプスタインのハーレムのひとりとセックスしたと主張している(https://www.theverge.com/2019/8/9/20798900/marvin-minsky-jeffrey-epstein-sex-trafficking-island-court-records-unsealed を参照のこと)。
これが事実であると仮定しよう(〔事実ではなかったと〕疑うべき理由は私には見当たらないが)。

「暴行」という語は、ミンスキーが力や暴力を用いたということを、何らかの不特定な形で推測させる。だが、あの記事ではそのようなことは述べられていない。
述べられているのは、彼ら〔ミンスキーと被害者のひとり〕がセックスをしたということだけである。

ここから様々なシナリオが考えられうるが、もっともらしいのは、被害者のひとりというのは、ミンスキーに自ら進んで自らを差し出したのだ、というシナリオである。被害者がエプステインに強制されていたと仮定するなら、エプスタインは、彼女が強制されているということをエプステインの多くの仲間たちに対して秘密にしておくべき理由をすべて、彼女に説明してやったはずである。

私〔ストールマン〕は糾弾の拡大の色々な事例を見て、糾弾の文言における「性的暴行」という言葉は絶対に間違っていると考えている。

何を批判しようと思うにしても、批判につきものである道徳的あいまいさを避けるべく、特定的な言葉を使って批判を述べるべきである。

リチャード・ストールマンが述べたことの中には、どこから手をつけたらよいのかわからないほどの誤りが含まれている。まず、ありがちで whiney な「彼は糾弾されているが有罪が確定したわけではない」式の防御術は、ストールマンは使っていない。否、ストールマンはもっと先まで進んでいる。じっさい、ストールマンは「仮に、マーヴィン・ミンスキーが児童の性的人身売買の犠牲者である未成年の女の子とセックスをした、と仮定してみよう」と述べている。

参照した文書は、ミンスキーがエプスタインのハーレムのひとりとセックスしたと主張している……それが事実であると仮定してみよう(〔事実ではなかったと〕疑うべき理由は私には見当たらないが)。

するとストールマンは、性奴隷にされた子供は、どういうわけか「自ら進んで」性奴隷にされたかも知れないと述べるのである。ストールマンが児童性的人身売買グループの犠牲者らを「ハーレム」などというとんでもない語で呼んでいることにも注意されたい。

ここから様々なシナリオが考えられうるが、もっともらしいのは、被害者のひとりというのは、ミンスキーに自ら進んで自らを差し出したのだ、というシナリオである。

これはテクノロジーのコミュニティで広く尊敬を集めている人物なのである。

これは MIT の客員研究者なのである。

MIT は、エプスタインの寄付を受け入れることによって、エプスタインの評価を浮上させるようなことは望んではいなかったと主張している。ところがご覧のように、MIT は評価を浮上させるはおろか、リチャード・ストールマンのような人物に資金を提供し、客員研究員として受け入れているのである。

まだある。どういうわけか、リチャード・ストールマンは、自分の意見を、学部生も参加している学科共通のメーリングリスト ("csail-related") に投稿するのが適切であると判断したのである。続くスレッドではこのようにも述べている:

「どの国におけることか、とか、被害者は18歳だったのか17歳だったのか、とかいうような些細なことにもとづいて『レイプ』を定義するのは道徳的に不条理だと考える」

これは「Giuffre 〔原註:証言した被害者〕は当時17歳で、これはヴァージン諸島ではレイプ〔原註:原文ママ〕にあたる」と述べたとある学生に対する返答である。

もう一度言う。このメーリングリストは学部生も参加している。学部生には「18歳か17歳」がいるはずである。

ショックだった。私は CSAIL の院生である友人と話を続けた。このメールのスレッドの全体を得ようと試みながら(私はこのメーリングリストには参加していなかった)。地方誌、全国誌、ニュースサイト、新聞、ラジオ局の記者たちにメールを送り始めた。考えが止まらなかった。自宅へと運転する45分間、普段ならポッドキャストか音楽を聞いている時間、私は完全な沈黙の中、ただ座っていた。

すぐに返信をくれた唯一の記者は WBUR の記者だったが、WBUR はこの情報をすぐに公表するつもりはなさそうであった。そういうわけで私は、ことのあらましを自分一人で書くかも知れないと、友人たちに知らせた。今日の仕事の後に書いて公表しても良かったのだが、集中できないかも知れなかったので、今やっている。

MIT は女性に値しない1
どのみち、この世界は女性に値しない。どうすれば STEM におけるジェンダーの問題を「修正」することができるか、STEM のプログラムに「もっと女子を増やす」ためにはどうすればいいか、といったことを訊ねてきた人たちのことを思い出した。「特殊なことを考えるのには男のほうが向いている」「テストステロンは数学の能力に結びついている」と誰かが言い出したときのことを思い出した。

こういう人たちが群れをなしているのが、心の中で見える。そして心の中で、私は立ち上がってその人たちに叫ぶ。時間と手がたくさんあったなら、その人たちの肩に手を当てて、その人たち一人一人の感覚を揺さぶることだろう。

問題は明白だ。

女は何も悪くない。STEM の女性は何も悪くない。いろいろな問題があっても、STEM に関係する分野が大好きな女性と女の子はたくさんいる。MIT の学士を4年で、PhD を7年で取得してしまう女性もいる。ところが、そうしたあとで、STEM の分野に携わり続けるべきかどうかを悩み始めるのだ。この分野は、この分野には、ひどい男があまりにも沢山いるからだ。

ジェフリー・エプスタイン。マーヴィン・ミンスキー。

リチャード・ストールマン。

トラヴィス・カラニック2。ジェームズ・ダモア3。テック業界とアカデミアとにおける、こういうパターンのハラスメント、ミソジニー、非犯罪化の長々と続くリスト。
これより前から、リチャード・ストールマンは問題のある人物として知られていた。これはストールマンのオフィスのドアの写真である。

〔リチャード・ストールマン 正義(とホットな女性)の騎士〕

これはそんなに真面目なものではないし、面白発言のたぐいですらあるが、だがストールマンは以前、放火するような (incendiary) メールを CSAIL のメーリングリストを送っていたと聞いている。友人のひとりは、ストールマンのメールを明示的に受信トレイから削除するフィルタを設定しているのだと冗談を言っていた。

私たちはどうしてこれを許容しているのだろう?

私たちはどうして、こういう冗談やコメントを許して、すべては単なる「slide4」だと矮小化してしまうのだろう?
私たちはどうして、こういうことが酷くなって公になって、私のような人が堪らなくなってこういう記事を書かなければならなくなるまで、放っておくのだろう?

私たちはどうして、片や MIT の大学院に入る女性やマイノリティが少ないことについて考え込みつつ、片や酷い男性研究者たちを支えなければならないのだろう?いや、支えているというだけではない――私たちは彼らをキャンパスへ招き入れ、招き入れた当の女性やマイノリティの学生と接触させることになるようにしているのである。

私たちはなぜ、こういう人たちをただ「天才」だからと言って許しておくのだろう?

ミシェル・オバマが言うように「彼らはそんなに賢くない」。STEM の分野に関しても、私は同意しなければならない。

テック業界の男性が女性にはできないことをやっているのを見たことなどない。むしろ、より謙虚でチーム志向な女性だってありうる[^4]。
他人を卑下するようなコメントが slide するのが許されるほどの賞賛に値する人物など一人もいない。特に、そういったコメントがレイプや暴力や児童性的人身売買を擁護するような場合については。

児童、

性的、

人身売買、である。

このことでサンディ・フック5のことを思い出した。知っての通り、当時、もしアメリカが子供たちの死に対して何ら責任を持とうとしなかったなら、私たちはその後も決して何をしようともしなかっただろう。
今、もし著名な技術の研究機関が、左派・右派・中道を問わず、問題のある男性を辞めさせようとしないならば、私たちは何もしない。決して。

たとえハーバード大が今後ともエプスタインへの寄付を受け取り、今後ともエプスタイン問題に対して沈黙を保とうとも、この問題が私たちのコミュニティの中で内輪の恥を晒していることなど、もはやどうでもよい。

私は母校を深く愛している。あそこは私が7歳の頃から目指していた場所だ。もし訊ねられれば、一番幸せな思い出、一番誇れる成果は、2013年12月14日の午後12時14分、合格通知の手紙を受け取った時であると、私は今でも答える。母校、すべてのテックや STEM の分野の研究機関、ひいてはすべての研究機関をよりよいものにしたいという強い思いをもって、私はこの記事を書く。

単にその人が「天才」だと思われているからとか、単にその人たちが力を持っていて、影響力があって、高い地位にある友人がいるからというだけの理由では、このような行為は看過されえない。

そういう人たちは、これほどまでに長い間、ジェフリー・エプスタインがレイプや児童人身売買をするのを許容してきた力なのだ。

少なくともリチャード・ストールマンは誰かをレイプしたというかどで糾弾されているのではない。だがそれは、私たちの最高水準なのだろうか?名門大学が守る水準なのだろうか?もしこれが MIT が守りたい水準なのだとしたら、もしこれが MIT が支持したい水準なのだとしたら、もしそうなら、よろしい、そんなものは焼き捨ててしまえ。

そうでないなら辞めさせよ。リチャード・ストールマンのような男たちや、今は隠れているに違いない他の多くの人たちを辞めさせよ。彼らは決して安んじていられるわけではなく、彼らは、私たちが思っているほどには、彼らの権力と地位の塔にかくまわれているわけではない、ということを #MeToo 運動は教えてくれた。

彼らを辞めさせよう。それが私たちのすべきことなのであれば。そして灰の山から、もっと良いものを建て直そう。


  1. "MIT does not deserve its women." うまい訳が思い浮かばなかった。 

  2. UBER の創業者。 

  3. 「反多様性」メモで Google を解雇。 

  4. うまい訳が思い浮かばない。 

  5. サンディフック小学校銃乱射事件 

Railsでポートフォリオを作ってみよう! vol.1 後編 (docker-compose導入〜rails構築編)

$
0
0

前回、Docker導入を行ったが、今回はdocker-composeの導入を行う。
(前回のDocker導入編をまだご覧になっていない人は→こちら)

docker-composeとは

Docker-composeとは、複数のコンテナをまとめて管理してくれるツールの名称。コンテナで作成した複数のサービスを構築・実行する手順を自動化し、管理を容易にしてくれる優れもの。
一つの専用ファイル(docker-compose.yml)を書いて、コマンドを叩くだけで使えるのも非常に便利。
Rails開発では複数のコンテナを使用する事が多々ある為Dockerを使うとなったら必須となってくる。
日本語訳版公式文章

つまりは覚えて損はない。

環境

今回の環境は以下の通り
・ruby 2.5.1
・rails 5.2.1
・MySQL 5.7

必要ファイルの確認

今回作成していくファイルは以下の4つ
・Dockerfile
・docker-compose.yml
・Gemfile
・Gemfile.lock

構築

下記から構築を行っていくが、作業の区切り区切りは中タグで区切っている為、途中から作業を再開したい場合などは右の一覧から探すのがオススメ。

作業ディレクトリの作成

作業ディレクトリの作成を行う。mkdirでファイルを作成しその中に入っていく。
今回「exampleApp」で作成を行っていく。

$ mkdir exampleApp
$ cd exampleApp

Dockerfileの作成

まずDockerfileをexampleApp直下に置く

vimが使える場合
$ vi Dockerfile

vimが使えない場合
$ touch Dockerfile
を行いDockerfileを作成し、Atomなどで開いて編集しても良い

そしてDockerfileを編集する

exampleApp/Dockerfile
#rubyの指定、今回は環境欄で言った通り2.5.1を指定している。
FROM ruby:2.5.1

#shellの実行を行い、パッケージのインストールを行う。
RUN apt-get update -qq && \
    apt-get install -y build-essential \
                       libpq-dev \
                       nodejs

#RUN mkdirでファイルを作成し、ENVで環境変数の設定を行っている。
#WORDIDは起点ディレクトリの設定を行っている。
#ちなみに下記に書いてある[/app_name]の名前は変更しなくても良い
RUN mkdir /app_name
ENV APP_ROOT /app_name
WORKDIR $APP_ROOT

#Gemfileの作成
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock

#Gemfileのbundle installを走らせる
RUN bundle install
ADD . $APP_ROOT

編集を行ったら保存してDockerfileは終了。

docker-compose.ymlの作成

Dockerfileと同じようにこちらもexampleApp直下に置く。

vimが使える場合
$ vi docker-compose.yml

vimが使えない場合
$ touch docker-compose.yml
を行いdocker-composeを作成し、Atomなどで開いて編集しても良い

こちらも開いて編集を行う。

examleApp/docker-compose.yml
#dbにある[MYSQL_ROOT_PASSWORD]のパスワードは後ほど使用する為覚えておく事
#インデントに注意する(インデントがずれている場合、エラーになる事が極めて高い)
#インデント表示無しVer
#versionは最新の3を使用
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    ports:
      - "3306:3306"

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app_name
    ports:
      - "3000:3000"
    links:
      - db

#インデント表示有りVer(こちらはインデント確認用として使用)
version: '3'
services:
..db:
....image: mysql:5.7
....environment:
......MYSQL_ROOT_PASSWORD: password
......MYSQL_DATABASE: root
....ports:
......- "3306:3306"

..web:
....build: .
....command: bundle exec rails s -p 3000 -b '0.0.0.0'
....volumes:
......- .:/app_name
....ports:
......- "3000:3000"
....links:
......- db

編集を行ったら保存してdocker-compose終了。

Gemfileの作成

今回railsは5.2.1を利用

vimが使える場合
$ vi Gemfile

vimが使えない場合
$ touch Gemfile
Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.1'

編集して保存。
現状はrailsだけ入っていれば大丈夫。

Gemfile.lockの作成

Gemfile.lockはただ単に作成だけ行う。
中の編集などは行わないので、

$ touch Gemfile.file

で完了。
これで必要なファイルの作成は終了。

rails newを行う

docker-composeコマンドを使用し、rails newを実行する。

$ docker-compose run web rails new . --force --database=mysql --skip-bundle

database.ymlの修正を行う

作成されたconfigファイルの中にあるdatabase.ymlの編集を行う。

vimが使える場合
$cd config
$vi database.yml

vimが使えない場合は直接configファイルに行き編集を行う。
exampleApp/config/database.yml
database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # MYSQL_ROOT_PASSWORDを記入
  host: db # docker-compose.ymlのservice名を記入

保存する。

docker-composeを起動する

ターミナルを確認。もしこの時点で

$ PC名: config $  

になっていたら [cd] を使用しexampleAppまで戻っておく

$ PC名: config $ cd ..
$ PC名: exampleApp $

コンテナを建てる

# コンテナをビルド
$ docker-compose build

# コンテナの作成&起動(別ターミナルが必要になる)
$ docker-compose up 
# コンテナの作成&起動(バックグラウンド)
$ docker-compose up -d

起動しおわったら localhost:3000に飛びいつものページ(Yay! You're on Rails!)が出ていることを確認して完了。

その他

サーバーの終了方法

いつものctrl + cだけでは、railsサーバーは閉じたけどdb(mysql)サーバーは閉じていないなどの不具合が発生する事があるため、以下のいずれかの方法で終了させる。

コンテナを停止だけさせたい場合
$ docker-compose stop

コンテナを停止させる + 削除する
$ docker-compose down

もしミスってctrl + cを行ってしまった場合はtmp/pids/server.pidファイルを削除し再度起動を行う。
そんなファイルないやんって時は、一度docker-composeを起動し、その状態で再度ファイルを探して削除を行い再起動すると治る場合がある。

なぜ2つの停止方法があるのか

他の理由もあるとは思うが、コンテナがある状態で新しくgemをインストールすると、サーバーの再起動を行っても反映されない事象がある。
原因としては簡単でDockerfileを見ればわかるように

RUN bundle install

を行っている。
docker-composeをstopさせただけでは以前のコンテナが残りっぱなしの為、docker-compose upを行ってもgemが対応しない。
なので、一回一回コンテナを削除して読み込ませないといけない。

そのため

gemは入れないけどとりあえず停止だけさせたい
→ $ docker-compose stop

gem新しく入れます、再度コンテナを作り直す理由が他にもあります
→ $ docker-compose down

と分けて使用する。

DBでもエラーが出た場合

docker-compose down を行い build したのはいいけど、dbが無いよなどのエラーが発生する場合がある。
その時は、

docker-compose run web rails db:create

を行う。

ちなみに

先ほど実行したdocker-compose run、
docker-composeではよく使うので覚えた方が吉。

docker-compose run [docker-compose.ymlで設定したサービス名] (使用したいコマンド)
→ docker-compose run web rails db:create

ローカルでbundle installしたい
docker-compose run web bundle install 

gitコマンド使いたい
docker-compose run web git add .

RSpec使いたい
docker-compose run web bin/rspec

シンプルな型 Pair[A]=(A, A) でいろいろな型クラスを実装してみる

$
0
0

とても簡単でわかりやすいデータ型 Pair[A]=(A, A) (同じ型の値のペア)について、Functor, Applicative, Monad, Traverse などを実装して型クラスを理解する Cats 入門者向け記事。

はじめに

たとえば (10, 20) というデータに、「2倍する」という関数を適用すると、直感的には (20, 40) になると考えるのが自然ではないだろうか。たぶん高校数学などでも「ベクトルのスカラー倍」のような形でなじみがある計算ではないかと思う。

同様に("abc", "de")に「文字列の長さ」という関数を適用すると(3, 2) が得られるのも、なんとなく自然な類推ではないだろうかと思う。

考え方としては、ペアの両方の値に同じ関数を単純に適用しているだけなのだけど、(1)ペアになっている値は同じ型であり、(2)関数を適用したあともペアであることは保たれるという暗黙の前提に注意して、ちょっと抽象的に書いてみると以下のようになる。

f: A → B と Pair[A] から、Pair[B] を得た。 あるいは f: A→B から、Pair[A] → Pair[B] を得た。

これと同じ形の操作を、Scala 標準のデータ型でも ListOption などの map として提供しているが、この共通性を Cats では Functor という型クラスに抽象化して、統一的な操作を提供している。この Functor として正式に認められるためには、Cats が要請するルールセットを ListOption と同様に満たさなければいけないが、後にみるように Pair もちゃんとそれを充足する。

実は Pair は、Functor 以外にもいろいろな型クラスインスタンスが書ける。実際に書いてみると、成立する型クラスが思っていたよりも多くて、面白かったので紹介したい。

進め方

対象

Cats にはいくつかの型クラス群があるが、F[_] を型パラメータにとる以下の階層に含まれるものについて、Pair のインスタンスを作ってみた1。先に結論を書いてしまうと、緑のティックが付いているものが型クラスのインスタンスが定義できたもので、赤のクロスが付いているものができなかったものになる2

cats-typeclasses.png

意外と多いと思ったのではないだろうか(自分はそうだった)。この後、一つずつ確認してみる。

趣向

  • もともと Cats の型クラス階層は、「非力だが制約の少ない」型クラスを頂点として、薄皮をかさねるように「強力だが制約の多い」型クラスに至るように構成されているが、この記事でもそれをなぞって少しずつ進める。
  • 実装コードを ??? で伏せたクイズのような形にして、実装例は畳み込んでおいた。一瞬考えてから実装例を見てみると、Pair でどう実装するかだけではなく、それぞれの型クラス固有の要請についての理解につながるのではないかと思う。3
  • 一番かんたんで自明な Functor を 1、個人的に一番難しかった FlatMap#tailRecM を 5として、難度を表示しておいた。といっても、たかが二つの値のペアなので、難度=5 でもある程度考えれば分かるレベルだと思う。
  • 型クラスごとに Cats が提供するルールセットを使って、それぞれの法則を Discipline テストで検証した。ただし、ルールセットを個別に解説するのはこの記事ではやめておいた4

実装

以下の型 Pair から、いろいろな型クラスを実装してみる。

type Pair[A] = (A, A)

たとえば Functor なら以下のようなものになる。

trait PairFunctor extends Functor[Pair] { ... }

さらに、以下のように Discipline を使ったテストも書く。ただしこの記事には載せずリンクだけ貼っておく。

class PairFunctorTests extends AnyFunSuite with Discipline {
  implicit val p: Functor[Pair] = new PairFunctor {}
  checkAll("Pair.FunctorLaws", FunctorTests[Pair].functor[Int, Int, String])
}
  • Scala は 2.13.1、Cats は 2.0.0 を使った。
  • 型クラスのインスタンス群のソースはここ
  • 型クラスのインスタンス群のテストコードはここ

Functor まわり

ここでは Invariant, Functor, Contravariant インスタンスを作ってみる。

Invariant

知名度があまり高くないかもしれないが、このInvariant は Cats の型クラス群の頂点の一つで、階層的に Functor の一つ上に当たる。したがって、モナド、アプリカティブ、Traverse など Functor の下層にある型クラス群は、自動的に Invariant の性質も持っていることになる。

と言ってもむずかしいものではなく、A => BB => A か、どちらかの関数があれば F[A] => F[B] が得られるような性質を表現できればよくて、Scala コードとしては下記のシグネーチャの imap を書くことになる。

trait Invariant[F[_]] {
  def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B]
  ...

Pair なら以下を実装することになるが、どう書けるだろうか?(難度=2)

trait PairInvariant extends Invariant[Pair] {
  def imap[A, B](fa: (A, A))(f: A => B)(g: B => A): (B, B) = ???
}

実装例
def imap[A, B](fa: (A, A))(f: A => B)(g: B => A): (B, B) = fa match {
  case (a1, a2) => (f(a1), f(a2))
}


簡単だけど、もしかすると g をどうやって使えばよいか悩んだかもしれない。単に捨てるだけでよくて、これで Discipline テストがちゃんと通る。

Functor

Invariant を継承して、以下のシグネーチャの map を追加すると Functor ができあがる。

trait Functor[F[_]] extends Invariant[F] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
  ...

Option や List などの操作で、普通の Scala コーディングでも頻繁に使う mapFunctor に関連していて、Cats の型クラスの中でも特に馴染み深いものだと思う。

Pair なら以下の map を実装すればよい。どう書けるだろうか?(難度=1)

trait PairFunctor extends Functor[Pair] with PairInvariant {
  def map[A, B](fa: (A, A))(f: A => B): (B, B) = ???
}

実装例
override def map[A, B](fa: (A, A))(f: A => B): (B, B) = fa match {
  case (a1, a2) => (f(a1), f(a2))
}


冒頭に書いたスカラー倍の問題そのもので、これは簡単だと思う。結局、Invariant と同じになる。

Contravariant

Invariant に下記のような contramap を追加すると、Contravariant になる。

trait Contravariant[F[_]] extends Invariant[F] {
  def contramap[A, B](fa: F[A])(f: B => A): F[B]
  ...

ただし B => A から (A, A) => (B, B) を得るのは無理なので、どうやらContravariant[Pair] は実装できない5

Semigroupal まわり

F[_] をあつかう型クラスの頂点の一つに、Semigroupal がある。ここでは Semigroupal以下、InvariantSemigroupalInvariantMonoidalContravariantSemigroupalContravariantMonoidalを見てみる。

Semigroupal

Semigroupal は、F[_] の中で型の積を作るような操作を提供する。以下のシグネーチャの product メソッドを実装する。

trait Semigroupal[F[_]] {
  def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
  ...

Pair の場合は以下を実装すれば良いが、どうなるだろうか。(難度=2)。

trait PairSemigroupal extends Semigroupal[Pair] {
  def product[A, B](fa: (A, A), fb: (B, B)): ((A, B), (A, B)) = ???
}

実装例
def product[A, B](fa: (A, A), fb: (B, B)): ((A, B), (A, B)) = (fa, fb) match {
  case ((a1, a2), (b1, b2)) => ((a1, b1), (a2, b2))
}


素朴に _1同士、_2同士をペアにすれば良い。行列の転置のような操作になる。

InvariantSemigroupal

SemigroupalInvariant を合わせるとInvariantSemigroupal となるが、ここまでに作った PairSemigroupalPairInvariant を合成するだけでよくて、Discipline が要求する ルールセットも自然と満たされる。

trait PairInvariantSemigroupal
  extends InvariantSemigroupal[Pair] with PairSemigroupal with PairInvariant

InvariantMonoidal

InvariantSemigroupalunit: F[Unit] を追加した型クラスが InvariantMonoidal となる。Pair の場合、型(Unit, Unit)の値を作ればよいが、どう書けるだろうか?(難度=2)

trait PairInvariantMonoidal extends InvariantMonoidal[Pair] with PairInvariantSemigroupal {
  def unit: (Unit, Unit) = ???
}

実装例
def unit: (Unit, Unit) = ((), ())


Unit の値がわからなければ、もしかすると悩んだかもしれない。

ContravariantSemigroupal, ContravariantMonoidal

ContravariantSemigroupalContravariant を継承するが、上で見たように Contravariant[Pair] は定義できない。このため ContravariantSemigroupal[Pair] も定義できず、またContravariantSemigroupal[Pair] を継承するContravariantMonoidal[Pair] も定義できないということになる。

Applivative 〜 Monad など

ここまでに見た、FunctorSemigroupal から新たな型クラス Apply が定義でき、その下の型クラス階層に ApplicativeMonad といった有名な型クラスが構成される。ここでも一歩ずつ順に見てみる。

Apply

FunctorSemigroupal を合成して6、さらに F[A => B] から F[A] => F[B] が得られる性質を付け加えると Apply になる。簡潔にした実装は以下のようなもの。

trait Apply[F[_]] extends Functor[F] with InvariantSemigroupal[F] {
  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
  ...

後述の Applicative を知っていれば、Applicativepure がないものと考えることもできる(Semigroupempty のない Monoid と理解できるのと同様に)。

Pairの場合、以下を実装すればよい。どう書けばよいだろか(難度=3)?

trait PairApply extends Apply[Pair] with PairFunctor {
  def ap[A, B](ff: (A => B, A => B))(fa: (A, A)): (B, B) = ???
}

実装例
def ap[A, B](ff: (A => B, A => B))(fa: (A, A)): (B, B) = (ff, fa) match {
  case ((f1, f2), (a1, a2)) => (f1(a1), f2(a2))
}


関数のペアと型Aのペアで、_1同士と _2同士を自然に適用する。ちなみに (f2(a1), f1(a2)) と書くと、コンパイルすることはできるが、Discipline テストで失敗する。

CommutativeApply

上述の通り ApplySemigroupalを継承しているが、Semigroupal#productApply#apを組み合わせると、下記のようなシグネーチャをもつ map2 が得られる。

def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z]

この map2 が可換となるような ApplyCommutativeApply となる。

ただし Pair の場合は、自然と可換性が成立して Discipline テストも成功する。

trait PairCommutativeApply extends CommutativeApply[Pair] with PairApply

Applicative

AF[_] の文脈にのせる操作 pureApply に追加したものが、Applicative になる。だから、もし「Applicative とは何か?」と聞かれるようなことがあったら、Scala+Cats 的には「Apply に pure を付け加えたものですが、なにか問題でも?」と、簡潔に答えることができる。

細部を省略したシグネーチャは以下のようなものになる(※ pure(()) により unitが提供できるので、実際の実装ではInvariantMonoidal も継承する形になっている)。

trait Applicative[F[_]] extends Apply[F] {
  def pure[A](x: A): F[A]
  ...

pure の実装は、例えば ListOption ならば、与えられた a:A について、それぞれ List(a)Some(a) だが、Pair の場合はどうだろうか?(難度=3)

trait PairApplicative extends Applicative[Pair] with PairApply {
  def pure[A](a: A): (A, A) = ???
}

実装例
def pure[A](a: A): (A, A) = (a, a)


サイズ2固定のコレクションを a でフィルするようなイメージの直感的な実装で、Discipline テストがちゃんと通る。

CommutativeApplicative

CommutativeApplyApplicative を合成すると CommutativeApplicative になる。Pair の場合、単に多重継承するだけで、それぞれの法則が満たされるようになる。特に追加のメソッドを実装する必要もない。

trait PairCommutativeApply extends CommutativeApply[Pair] with PairApply

FlatMap

だんだんモナドに近づいてきた。

Cats では、Applyに下記シグネーチャの flatMap, tailRecM を付け加えると FlatMapとなる7

trait FlatMap[F[_]] extends Apply[F] {
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
  def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B]
}

別々に見てみる。まず flatMapから。

おさらいすると、F[A] => F[B]を得る前提として A => B が使えるのが Functor、さらにF[A => B]も使えるのが Apply(Applicative)だった。ここでさらに A => F[B] も使えるのが FlatMap(そして後述のMonad) になる。

Pair の場合、以下を実装すればよい。どう書けるだろうか?(難度=4)

trait PairFlatMap extends FlatMap[Pair] with PairApply {
  def flatMap[A, B](fa: (A, A))(f: A => (B, B)): (B, B) = ???
...

実装例
def flatMap[A, B](fa: (A, A))(f: A => (B, B)): (B, B) = map(fa)(f) match {
  case ((b1, _), (_, b2)) => (b1, b2)
}


fa:(A,A) の二つの A値にそれぞれ f を関数適用すると(map)、得られる型は ((B,B),(B,B)) となるから、これを(B, B)にする必要がある。言い換えると Pair[Pair[B]] を平らにして Pair[B] にしている訳で、これが FlatMap の "flat" たるゆえんでもあるが、ここでは両端の要素だけを残すことで実現している。値を捨てちゃって良いのだろうかと心配になるが、これでちゃんと Discipline テストも通る。

次に tailRecM を見てみる。これは代数や圏論からの要請というより、スタックセーフを実現するための実装上の仕組みで、シグネーチャを再掲すると下のようなものだった。

def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B]

関数f の使い方としては、f(a) の結果が Right 値なら結果に含めて、Left値なら再び f を適用して計算を継続するようにすればいい。ただし、うまく末尾再帰を構成してスタックオーバーフローを防ぐ必要がある。

Pair なら以下を実装すればよいが、どうなるだろうか?(難度=5)

trait PairFlatMap extends FlatMap[Pair] with PairApply {
...
  def tailRecM[A, B](a: A)(f: A => (Either[A, B], Either[A, B])): (B, B) = ???

実装例

先に失敗例を示すと以下のようになる。
def tailRecM[A, B](a: A)(f: A => (Either[A, B], Either[A, B])): (B, B) = f(a) match {
  case (Right(b1), Right(b2)) => (b1,                 b2)
  case (Left(a1),  Right(b2)) => (tailRecM(a1)(f)._1, b2)
  case (Right(b1), Left(a2))  => (b1,                 tailRecM(a2)(f)._2)
  case (Left(a1),  Left(a2))  => (tailRecM(a1)(f)._1, tailRecM(a2)(f)._2)
}

この実装だと、計算結果の値自体には問題がないが、末尾再帰にならないのでスタックセーフティが得られない。実際にスタックオーバーフローが発生するのは、この FlatMap のルールセットではなくて次のモナドのルールセットだけど、tailRecM の実装なのだからちゃんと tailrec にしておきたい。

末尾再帰を構成したスタックセーフな実装例は、以下のようなものになる。

def tailRecM[A, B](a: A)(f: A => (Either[A, B], Either[A, B])): (B, B) = {
  @scala.annotation.tailrec
  def first(a: A): B = f(a) match {
    case (Right(b), _) => b
    case (Left(a),  _) => first(a)
  }
  @scala.annotation.tailrec
  def second(a: A): B = f(a) match {
    case (_, Right(b)) => b
    case (_, Left(a))  => second(a)
  }
  (first(a), second(a))
}


CommutativeFlatMap

ApplyApplicative に、それぞれ対応する CommutativeApplyCommutativeApplicative があったように、FlatMap にも CommutativeFlatMap がある。Pair の場合、CommutativeFlatMap[Pair] も、FlatMapCommutativeApplicative を継承するだけで、自然とDiscipline のルールセットを満たすようになる。

trait PairCommutativeFlatMap extends CommutativeFlatMap[Pair] with PairFlatMap with PairCommutativeApply

Monad

ApplicativeFlatMap を合成すると、それだけで Monad になってしまう。具体的には、Applicative#pure と、FlatMap#flatMap(と tailRecM)があれば Monad になって、Discipline が提供する「モナド則」も自然と満たされる。

数学的にモナドを理解しようとすると、よく知られている「モナドとは自己函(ry」にしても、随伴とかを使った構成にしても、それなりに段階を踏んで理解を積み上げていく必要があるけど、Scala+Cats での Monad は、ここまでで見たように単に ApplicativeFlatMap を多重継承したトレイトにすぎず、予めお膳立てされた Discipline ルールセットについてテスト実行がグリーンになりさえすれば、プログラミング技術としては十分だったりする。

CommutativeMonad

ApplyApplicativeFlatMap に、それぞれ対応する Commutative版 があったように、Monad にも CommutativeMonad がある。Pair の場合も、下記のような継承構成で自然と Discipline のルールセットを満たす可換性が得られる。

trait PairCommutativeMonad extends CommutativeMonad[Pair]
  with PairMonad
  with PairCommutativeFlatMap
  with PairCommutativeApplicative

Foldable〜Traverse まわり

Cats 型クラス階層の頂点の一つに UnorderedFoldable がある。階層の下の方には、わりとよく使われる FoldableTraverse が含まれるが、ここでは Pair[A]=(A, A) をサイズ2固定のコレクション8と捉えてインスタンスが作れるか試してみる。

UnorderedFoldable

UnorderedFoldable では、以下のようなシグネーチャのメソッドを実装する。

def unorderedFoldMap[A, B: CommutativeMonoid](fa: F[A])(f: A => B): B

B が可換モノイドであることに注意して、Pair の場合ならば以下を実装すればよい。どのように書けるだろうか?(難度=3)

trait PairUnorderedFoldable extends UnorderedFoldable[Pair] {
  def unorderedFoldMap[A, B: CommutativeMonoid](fa: (A, A))(f: A => B): B = ???
}

実装例
def unorderedFoldMap[A, B: CommutativeMonoid](fa: (A, A))(f: A => B): B = fa match {
  case (a1, a2) => f(a1) |+| f(a2)
}


CommutativeMonoid の意味が、単位元と可換な二項演算をもつことだとわかれば簡単だと思う。空がありうるようなF[_]、たとえば List や Option なら単位元も利用することになるが、Pair の場合、空はありえないので二項演算のみを利用する。

UnorderedTraverse

UnorderedFoldable に、以下のようなシグネーチャの unorderedTraverse を追加すると、UnorderedTraverse になる。

trait UnorderedTraverse[F[_]] extends UnorderedFoldable[F] {
  def unorderedTraverse[G[_]: CommutativeApplicative, A, B](sa: F[A])(f: A => G[B]): G[F[B]]
  ...

後述の Traverse#traverse と似ているが、G の型制約が CommutativeApplicative となっていて、Traverse が要請するApplicativeより厳しいために、その分逆に型クラスとしては自由度が高く、型クラス階層で上の方に位置している。

Pair をUnorderedTraverse とするには以下を実装すればよいが、どうかけるだろうか?(難度=3)

trait PairUnorderedTraverse extends UnorderedTraverse[Pair] with PairUnorderedFoldable {
  def unorderedTraverse[G[_]: CommutativeApplicative, A, B](sa: (A, A))(f: A => G[B]): G[(B, B)] = ???
}

実装例
def unorderedTraverse[G[_]: CommutativeApplicative, A, B](sa: (A, A))(f: A => G[B]): G[(B, B)] =
  sa match {
    case (a1, a2) => f(a1) product f(a2)
  }
}


CommutativeApplicative を階層上の上にたどると Semigroupal に突き当たるので、そのメソッド product を使って G[(B, B)]を作れば良い。

Foldable

UnorderedFoldablefoldLeftfoldRight を付け加えると Foldable になる。

trait Foldable[F[_]] extends UnorderedFoldable[F] {
  def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B
  def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B]
  ...
}

まず foldLeft から。Pair ならば以下を実装すればよいが、どうなるだろうか?(難度=2)

trait PairFoldable extends Foldable[Pair] {
  def foldLeft[A, B](fa: (A, A), b: B)(f: (B, A) => B): B = ???
  ...
}

実装例
def foldLeft[A, B](fa: (A, A), b: B)(f: (B, A) => B): B = fa match {
  case (a1, a2) => f(f(b, a1), a2)
}


普通の Scala コードの List操作などから、簡単に類推できるのではないだろうか。

次に foldRight。こちらは Eval を使うので難度が高まる。遅延評価させるために、あえて導入している Eval なので、単に型合わせだけしてコンパイルを通しただけでは、Discipline テストで失敗する可能性がある。Pair の場合、以下を実装すればよいがどうなるか?(難度=4)

trait PairFoldable extends Foldable[Pair] {
  ...
  def foldRight[A, B](fa: (A, A), lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = ???
}

実装例
def foldRight[A, B](fa: (A, A), lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
  fa match {
    case (a1, a2) => Eval.defer(f(a1, Eval.defer(f(a2, lb))))
  }


右から畳み込む操作自体は全然むずかしいものではないが、Eval.defer に気づかないとなかなか Discipline テストが通らないかもしれない。例えば f(a1, f(a2, lb)) のようにしてしまうと、lazy であることを要求するいくつかのルールが満たされなくなる。

Reducible

Foldablenon empty 版が Reducible で、下記シグネーチャの reduceLeftToreduceRightTo が追加される。

trait Reducible[F[_]] extends Foldable[F] { self =>
  def reduceLeftTo[A, B](fa: F[A])(f: A => B)(g: (B, A) => B): B
  def reduceRightTo[A, B](fa: F[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B]
  ...

foldLeft/Right では初期値を明示的に与えていたが、reduceLeft/RightTo では、少なくとも1つのA型値があることを前提にしているので、初期値の代わりに f: A=>Bを与える。Pair の場合は以下を実装すればよいがどうなるか?(難度=3)

trait PairReducible extends Reducible[Pair] with PairFoldable {
  def reduceLeftTo[A, B](fa: (A, A))(f: A => B)(g: (B, A) => B): B = ???
  def reduceRightTo[A, B](fa: (A, A))(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = ???
}

実装例
def reduceLeftTo[A, B](fa: (A, A))(f: A => B)(g: (B, A) => B): B = fa match {
  case (a1, a2) => g(f(a1), a2)
}
def reduceRightTo[A, B](fa: (A, A))(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = fa match {
  case (a1, a2) => g(a1, Eval.later(f(a2)))
}


reduceRightToEval.laterEval.now でも問題ない(多分。少なくとも Discipline 的にはグリーン)。

Traverse

FoldableUnorderedTraverseFunctor を継承して、さらにメソッド traverse を付け加えると、おなじみの Traverse になる。traverse のシグネーチャは以下のようなものだった。

trait Traverse[F[_]] extends Functor[F] with Foldable[F] with UnorderedTraverse[F] {
  def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]]
  ...
}

Pair の場合、下の未実装部分を書き足せば Traverse[Pair] が得られるが、どう書けるだろうか?(難度=2)

trait PairTraverse extends Traverse[Pair] with PairFunctor with PairFoldable {
  def traverse[G[_]: Applicative, A, B](fa: (A, A))(f: A => G[B]): G[(B, B)] = ???
}

実装例
override def traverse[G[_]: Applicative, A, B](fa: (A, A))(f: A => G[B]): G[(B, B)] =
  fa match {
    case (a1, a2) => f(a1) product f(a2)
  }


unorderedTraverse と同じ実装で良いが、G の型制約が traverse の方がゆるいので、traverse の定義で unorderedTraverse を使うことはできない。逆に、unorderedTraverse の定義で traverse を使うことは可能。

NonEmptyTraverse

Traverse にメソッド nonEmptyTraverse を追加すると、型クラスNonEmptyTraverseになる。nonEmptyTraversetraverse と似ているが、F[_]NonEmpty であることがわかっているため、型パラメータ Gの制約が少し弱まり、Applicativeから Applyになる。

Pair を NonEmptyTraverse にするには下記を実装すればよいが、どう書けるだろうか?(難度=2)

trait PairNonEmptyTraverse extends NonEmptyTraverse[Pair] with PairReducible {
  def nonEmptyTraverse[G[_]: Apply, A, B](fa: (A, A))(f: A => G[B]): G[(B, B)] = ???
}

実装例
def nonEmptyTraverse[G[_]: Apply, A, B](fa: (A, A))(f: A => G[B]): G[(B, B)] = fa match {
  case (a1, a2) => f(a1) product f(a2)
}


もともと traverse でも Applicative#pure は使っていなかったので、結局まったく同じコードで済む。

CoflatMap、Distributive など

Functor からの継承ラインのうち、ApplyTraverse 以外のものについて。

CoflatMap

すでに見た FlatMapA => F[B]から F[A] => F[B]を得るものだったが、これと逆の F[A] => Bから F[A] => F[B] を得る性質を Functorに追加すると、CoflatMapとなる。

trait CoflatMap[F[_]] extends Functor[F] {
  def coflatMap[A, B](fa: F[A])(f: F[A] => B): F[B]
  ...

Pair の場合、以下の未実装部分を書けばよいが、どうなるだろうか?(難度=3)

trait PairCoflatMap extends CoflatMap[Pair] with PairFunctor {
  def coflatMap[A, B](fa: (A, A))(f: ((A, A)) => B): (B, B) = ???
}

実装例
def coflatMap[A, B](fa: (A, A))(f: ((A, A)) => B): (B, B) = {
  val x = f(fa)
  (x, x)
}


A のペアからfによって得られる B は1個だけだが、Applicative#pureと同じような考え方でタプルを埋めると、それで Discipline のルールセットも満たされる。

Comonad, Bimonad

Monad の双対である Comonad を得るには、上で書いた flatMap の双対の coflatMapと、あとは pure: A => (A, A) の双対の extract: (A, A) => Aが書ければよい。

単純に考えると、_1_2を返せば良さそうに思えるが、しかし実はこれだと Comonad のルールセットを満たせない(例えば、coflatMap と extract を組み合わせると、元の (A, A) に復元できるといったプロパティがある)。なので Comonad[Pair] は成立しない。従ってまた、Comonad を継承とする Bimonad も成立しない。

Distributive

A => F[B] から G[A] => F[G[B]] が得られるようなメソッド distributiveFunctorに追加すると、Distributive になる。

trait Distributive[F[_]] extends Functor[F] {
  def distribute[G[_]: Functor, A, B](ga: G[A])(f: A => F[B]): F[G[B]]
  ...

Traverse の双対になっていて9、以下のような対応関係がある。

型クラス この射から この射を得る G の条件
Traverse[Pair] A => G[B] (A, A) => G[(B, B)] Applicative
Distributive[Pair] A => (B, B) G[A] => (G[B], G[B]) Functor

Scala コードとしては以下の未実装部分を補えばよいが、どうなるか?(難度=3)

trait PairDistributive extends Distributive[Pair] with PairFunctor {
  def distribute[G[_], A, B](ga: G[A])(f: A => (B, B))(implicit G: Functor[G]): (G[B], G[B]) = ???
}

実装例
def distribute[G[_], A, B](ga: G[A])(f: A => (B, B))(implicit G: Functor[G]): (G[B], G[B]) = {
  val gpb: G[(B, B)] = ga map f
  (gpb.map(_._1), gpb.map(_._2))
}


G が Functor であることを利用して、gaf から G[Pair[B]] を得てから、内箱と外箱を入れ替えて Pair[G[B]] とすればいい。

SemigroupK など

おさらいすると、Cats の K のつく型クラスは、任意の型パラメータで成立する操作、つまりF[A] なら A にかかわらずF[_]の性質のみで成立する操作を提供するものだった。例えば List[A] なら、型 A が何であろうとリストの連結という二項演算があり、空リストという単位元がある。これを Pair の場合でみてみる。

SemigroupK

SemigroupK は、二つのF[A] をあわせて一つのF[A] にするメソッド combineK を持つ。

trait SemigroupK[F[_]] {
  @simulacrum.op("<+>", alias = true)
  def combineK[A](x: F[A], y: F[A]): F[A]
  ...

SemigroupK なら二組の (A, A) をあわせて一組の (A, A) にするから、4つの A値を 2個にすることになる。A について前提を置かないのが、「Kのつくクラス」なので、A同士を合成することはできない。したがって半分すてて 2個だけとるしかない。どのように書けるだろうか。(難度=2)

trait PairSemigroupK extends SemigroupK[Pair] {
  def combineK[A](x: (A, A), y: (A, A)): (A, A) = ???
}

実装例
def combineK[A](x: (A, A), y: (A, A)): (A, A) = (x, y) match {
  case ((x1, _), (_, y2)) => (x1, y2)
}


2個の A値の取りかたは associatiive law が成立すればいい。実は上のとり方だけが正解ではなくて、x や y をそのまま返したりしても、Discipline テストは上手く行く。逆に失敗するパターンを探してみると、SemigroupK の結合律の理解の助けになるかもしれない。

MonoidK, Alternative

Monoid が単位元を提供するのと似たように MonoidK は「空」を提供する。これも型パラメータに依存しないものが求められ、たとえば List なら 空リスト、Option なら Noneでよいが、Pair の場合は単位元に相当するものはない。したがって MonoidK[Pair] は成立しないとわかる。

またさらに MonoidK に依存する(継承する)Alternative も、Pair では成立しないことになる。

おわりに

  • 質問者:「モナドとはなんですか?」
  • この記事を読んだ Cats ユーザ:「ApplicativeFlatMap を継承した Monad トレイトの実装で、Discipline テストの実行結果がグリーンになるものですが、なにか問題でも?」

  1. A を型パラメータにとる Eq系、Monoid系、F[_,_]を型パラメータにとる BiFunctorArrow 系、あるいは F[_] でも Cats Effect や Cats MTL に含まれるものもあるが、ここでは扱わない。 

  2. もとの画像はここ 

  3. 『Learn Better』という一般向けの学習理論の本によれば、ただ読むだけという行為は、どれだけマーカーを引こうが、あるいは何度読み返そうが、学習効果はぜんぜん薄いというのが、心理学でも脳科学でも無数のエビデンスに支持された結論らしい。そこで同書では本の中の要所要所に、小テストを入れて理解と記憶の定着を支援していたが、この記事でもそれにならって、「学習」を「活動」につなげるためにクイズ形式を取り入れてみた。 

  4. 【理由1】かなり数が多い、【理由2】あらかじめ法則を知悉していなくても、テストがコケたときに調べるくらいがコスパが良い、【理由3】自分も含め、ほとんどのプログラマは数学徒ほど証明や法則が好きではない(たぶん)。 

  5. Contravariant に馴染みがない人は、逆にどういうF[_]Contravariant になるのか考えてみると理解が深まるかもしれない。 

  6. 図では Semigroupal だけど、実装上は InvariantSemigroupal。 

  7. 個人的には、代数的性質から要請される flatMap と、実装都合の tailRecM が同じトレイトに含まれるのは、異なる関心事が混在してしまっている気がする。Scalaz ではたしかちゃんと分離されていた。 

  8. Shapeless の Sized で固定サイズのコレクションを表現することもできる。 

  9. 以前、調べてみた記事を書いた。 

Docker初心者未満向け

$
0
0

はじめに

  • 自己紹介:UbuntuでPythonを書いてデータ分析とか異常検知してます
  • CUDAのバージョン管理のためにDockerをやろうと思った
  • 専門用語が多すぎて脳が混乱したので用語集を作った
  • これからDockerを始めたいけどガチで何もわからないという人向けにまとめた
  • PCで見てほしい(スマホQiita勢、いるのか…?)

Dockerことはじめ

  • いろんな仮想環境構築が簡単にできて嬉しいシステム
    • 仮想環境とは:好きなOS+好きなソフトと思っとけばOK
  • 今までの仮想化(ホストOS型仮想化)の悪いところ
    • 仮想環境がホストOSや仮想化ソフトウェアのバージョンに依存してしまう
      • DockerはホストPCの中に全く別のPCを用意する様なものなのでホストの環境に依存しない
      • つまり、いつ誰が使っても同じ結果になる=これを「冪等性」という
      • 冪等性がなくてつらいことになる例
        • web系の人:開発環境と本番環境が違って動かない
        • 機械学習の人:CUDAとかミドルウェアのバージョン管理が死ぬほどめんどくさい
    • 動作がもっさり、ファイル容量が大きいので共有が大変
      • Dockerは仮想環境(Container)の型(Image)を保存・配布する方式なので、管理や共有が楽

Docker運用の流れ

  • ホストPCにDockerをインストール
  • Dockerfileを書く
  • Dockerfileを元に、Docker Imageを作る(build)
  • Docker Imageを元に、Docker Containerを作り、仮想環境を有効にする(run)
  • 仮想環境内でなんやかんや好きなことをする
  • 終わったらContainerを停止させ(stop)、削除する(rm)
  • 「この前と同じ仮想環境作りたいな〜」と思ったら、同じImageを元にContainerを作る(run)
  • Tips
    • Imageは基本的に削除しないけど、もう使わないものがあまりに増え過ぎたら消してOK
    • Docker HubというGithub的なリポジトリから既存のImageをダウンロードできる(pull)

用語集(超基礎)

  • Dockerfile
    • 拡張子のないテキストファイル。DSLというDocker用言語を使って「どんな仮想環境を作りたいか」を書くもの
    • DSL言語の例
      • FROM:どのOSやミドルウェアの環境を作るか
      • RUN:Imageを作る時に、どういうコマンドを実行するか
      • COPY:どのファイルをホストPCからコンテナに移動させるか
  • Docker Image
    • Dockerfileを基に作られるもの。後述のContainerの型のようなもの
    • Imageを作ることをbuildと言う
    • オブジェクト指向的に言えばクラス
    • Docker Hubで公開されてるImageをDLしてきてもOK。これをpullという
  • Docker Container
    • Docker Imageを基に作られる仮想環境そのもの
    • オブジェクト指向的に言えばインスタンス
    • Containerを作り実行することをrunという
    • Imageの形で保存・配布して、仮想環境を作りたくなったらContainerにしてね〜という感じ
    • やりたい事が終わったら消す。Imageは残しておき、同じ環境が作りたくなったらまたrunさせる

用語集(ちょっとむずかしい)

  • Docker Engine
    • 常駐アプリ。Dockerシステムの親玉
  • Docker Compose
    • yml形式のテキストファイル
    • 1個のホストPC上で複数個のコンテナを動かす時、その方法を指示する
    • 複数個のコンテナをいっぺんに起動とかもできて便利
  • Docker Machine
    • 「Dockerを持つホストPC」の中に「Dockerを持つPC」環境を作れる
    • クラウド上にDocker環境作る時に便利
  • Docker Swarm
    • 複数台のホストPCがある時、それらをまとめて制御できる
    • 例えば、ホストをまたいだコンテナ間の通信をどう制御するかなど
    • これを「オーケストレーションシステム」という
  • Service
    • ホストPCが1台&コンテナが1個 → container runコマンドでコンテナを起動
    • ホストPCが1台&コンテナが1個 → Composeを使ってまとめてコンテナを起動
    • ではホストPCが複数台のときは? → Serviceというコンテナのまとまりを作って起動
    • 1つのアプリしか扱えない
  • Stack
    • Serviceのまとまり
    • 複数のServiceを扱うことで、複数のアプリを扱うことができるようになる
  • Kubernetes
    • Swarmと同じく、オーケストレーションシステムの1つ
    • Compose, Swarm, Stackを合わせたような便利なやつ

Dockerにおけるデータ管理

  • データ管理関連
    • 仮想環境作ってからいちいちデータをダウンロードしてたらめんどくさい
    • ホストPC上にデータを管理して、それをコンテナにマウントする手法が取られる
  • データ通信関連
    • コンテナ間で通信できるし、ホストをまたいで通信する事もできる

Dockerを勉強しててひっかかったところ

  • 「Dockerfile」という名前の情報のなさ
    • Dockerfileという固有名詞があると最初わからなかった
    • Docker関係のファイル全般のことだと思ってた
  • Docker Imageもコンテナっぽいこと
    • Imageに「OS+ミドルウェア+アプリ」を放り込むんだからコンテナ感あるよね
    • あくまでContainerは仮想環境の実体、Imageはその型

おわりに

  • 自分の理解が進んだら随時追記します
  • 「ここがわからなかった」「ここがまちがってる」「わかりやすかった」などコメントお待ちしてます

参考

ROLL-A-BALL TUTORIAL #4

$
0
0

Way to move the camera

1. Create a component which traces “Player”

It creates a component which trace “Player”. This component has some function following.

  1. Get the position of “Player”.
  2. Adjust a coordinate of the Player’s position every frame.

So, at first, it creates the “Follow Player” component. Then add “Main Camera” to it.

  1. Select “Main Camera” in Hierarchy View.
  2. Click the “Add Component” button in Inspector View.
  3. Select “New Script” and add “Follow Player”.
  4. Move “FollowPlayer.cs”, is under Assets, to Assets/Script folder in Project Browser.

Next, double click “FollowPlayer” to invoke code editor.
1.png

2. Way to trace player

It makes tracing function from getting an object’s position. Write a source code below in “FollowPlayer.cs”.

FollowPlayer.cs
using UnityEngine;
using System.Collections;

public class FollowPlayer : MonoBehaviour
{
    public Transform target;    // Reference to target

    void Update ()
    {
        // set target’s position to oneself
        GetComponent<Transform>().position = target.position;
    }
}

Look component of “Main Camera” and confirm what add term of target in “Follow Player”. Drag & drop “Player” onto this term.
2.png
Let’s start the game. Game View shows a view like the below picture as FPS.
3.png

3. Set offset to a component

Change a camera point like TPS that have an appropriate distance to ball. So, add a function which maintains the distance between “Player” and “Main Camera” when starting the game. The function is created by below sub-functions.

  1. Get a relative distance between “Player” and “Main Camera” when starting the game.
  2. Set the position of the camera to “Player’s position + relative distance” every frame.

At first, Set the position and rotation to “Main Camera” like a below picture.
4.png

Next, Change a source code.

FollowPlayer.cs
using UnityEngine;
using System.Collections;

public class FollowPlayer : MonoBehaviour
{
    public Transform target;    // Reference to target
    private Vector3 offset;     // relative distance

    void Start ()
    {
        // Get relative distance between “Player” and “Main Camera”
        offset = GetComponent<Transform>().position - target.position;
    }

    void Update ()
    {
        // Set “Player’s position + relative distance” to oneself
        GetComponent<Transform>().position = target.position + offset;
    }

Let's play the game.
5.png

ROLL-A-BALL TUTORIAL #5

$
0
0

Adding the function of deleting the item

We add function of deleting the item in the game. The function is "Items disappear when the player touches items placed on the stage". It has the following function.
1. Create many items
2. Detect when the player touches item
3. Delete touching item

1. Create an object

At first, it creates an object that is a source of the item.
1. Click the “Create” of the “Hierarchy” view.
2. Click “3D Object → Capsule”.
3. Change a name into “Item” in the created Capsule.

1.png
Change position and scale for the “Item”.
2.png

  • Position(x: 0, y: 1, z: 0)
  • Scale(x: 0.5, y: 0.5, z: 0.5)

2. Create an object

We write out the object construction information as “Prefab” so that we can produce this created “Item” easily. Let's create a folder for “Item” and store prefab there.
1. Click the “Create” in the “Project” view.
2. Edit folder name to “Prefab”.

3.png
We write out the “Item” as “Prefab”. It is successful if the "Item" object changes the blue icon.
1. Select the “Item” in the “Hierarchy” view.
2. Drag and drop the “Item” object to the “Prefab” folder of the “Project” view.
4.png
5.png

3. Place the "Item" object

We place the created item into the "Scene".
1. Select “Item” in the "Prefab" folder of the "Project" view.
2. Drag and drop it onto the "Scene" view.

The object that was set up was placed in the "Scene" view. We will place items in a circle.
6.png

4. Contact judgment between “Player” and “Item”

Add contact judgment into Item. This function isn't a standard feature. We need to add a new component.
1. Select the "Item" object of the "Hierarchy" view.
2. Select “Add Component → New Script” of the “Inspector” view.
3. Change a name into "Item" and Click a "Create and Add" button.

At first, check the usable contact judgment call-back from API of Monobehaviour. This time, we add "OnTriiggerEnter" of contact judgment API. "OnTriiggerEnter" judgment only triggers. We add call-back in “Item.cs”.

Item.cs
using UnityEngine;
using System.Collections;

public class Item : MonoBehaviour
{
    // The call-back of contact trigger
    void OnTriggerEnter (Collider hit)
    {
    }
}

5. Change Item's contact judgment into the trigger

Since the judgment was set to Trigger, contact judgment must also be set to Trigger. Set Collider setting of Item to Trigger.
1. Select the "Item" object of the "Hierarchy" view.
2. Check “IsTrigger” of “CapsuleCollider” Component of the “Inspector” view.
7.png

6. Contact judgment with “Player”

It has become possible to make contact judgment with Trigger. However, we want to do the judgment with "Player" only.
There are several ideas. This time, we'll make it "check tag". The augment of OnTriggerEnter, "hit" contains the contact target information. Check this tag that contacted anything, and modify the "Item" component as follows to do special processing if it is "Player".

Item.cs
using UnityEngine;
using System.Collections;

public class Item : MonoBehaviour
{
    // Call-back called upon trigger of contact
    void OnTriggerEnter (Collider hit)
    {
        // Is the contact target “Player” tag?
        if (hit.CompareTag ("Player")) {

            // Do some processing
        }
    }
}

7. Set tag on “Player”

Also, set the "Player" object. Since we wrote the process of ‘When in contact with an object that has "Player tag"’, we also need the "Player tag" for the "Player" object.
1. Select the "Player" object of the "Hierarchy" view.
2. Change tag of "Inspector" view to "Player".
8.png

8. Delete Item at contact judgment

Set to delete objects when touching. Use the Destroy method to delete it.
Destroy is a method to delete an object. The object specified by the method will be deleted and disappear from the game.

Item.cs
using UnityEngine;
using System.Collections;

public class Item : MonoBehaviour
{
    // Call-back called upon trigger of contact
    void OnTriggerEnter (Collider hit)
    {
        // Is the contact target “Player” tag?
        if (hit.CompareTag ("Player")) {

            // Destroy the GameObject with this component
            Destroy(gameObject);
        }
    }

This will destroy the “Item” object when contact “Player”.
9.png
10.png

9. Update “Prefab”

Currently, only the "Item" object that has been set up will delete. Then update the value of "Prefab" so that the object placed as "Prefab" has the same setup as well.
1. Select the "Item" object of the "Hierarchy" view.
2. Click the “Apply” button of the “Inspector” view.
11.png

10. Organize “Item”

Finally, we will organize the items. The process is the same as setting the Stage. However, the item isn't a static object. We don't check "Static".
1. Click the “Create” in the “Hierarchy” view.
2. Select “Create Empty”.
3. Change a name into “Items”.
4. Select all the created "Item" objects and drag and drop to the "Items" object.
12.png

ROLL-A-BALL TUTORIAL #6

$
0
0

Adding UI of this game

We add UI of this game. It is a very simple function. it is only “Display the number of remaining items” It has the following function.
1. Count the number of remaining items.
2. Display items by UI

図1.png

1. Preparing UI of displaying “the number of remaining items”.

At first, Let’s create the UI. Simply, We create a UI that displays the number of remaining items in the bottom left on the screen.

1-1. Set the “Canvas”

At first, We create “Canvas” that displays UI.
1. Click the “Create” of the “Hierarchy” view.
2. Click “UI → Canvas”.

図2.png

Set the supposed size for the “Canvas”.
1. Click the “Canvas” object in “Hierarchy” view.
2. Set the "UI Scale Mode" to "Scale With Screen Size" in Canvas Scaler.
図3.png

1-2. Set the “Text”

Next, we create the text.

  1. Click the “Canvas” object in “Hierarchy” view.
  2. Click “UI → Text”.
  3. Rename the created Canvas> Text object as ScoreLabel in the Inspector view.

図4.png

You can be seeing “Text”.
Move the “Text” to the center and adjust the font size.

  1. Click the “Canvas>ScoreLabel” object in “Hierarchy” view.
  2. Set the value of “Rect Transform” to the following. (PosX : -230, PosY : -230, Width : 300, Height : 100)
  3. Set “Font Size” of “Text” to “60”.
  4. Set “Text” of “Text” to “0”.

図5.png

図6.png

2. Create the “Game Controller”

Next, we create a system to notify the “ScoreLabel” that created “the number of remaining Items”.

There are many ways to implement this system, but this time we create it by simplist way that “GameController” manages. And in Unity "GameController" should manage to the progress of the entire game such as the number of items. This "GameController" counts “the number of remaining Items” and has a system to notify if it is changing.

Let’s create this "GameController".

  1. Click the “Create” of the “Hierarchy” view.
  2. Click the “Create Empty”.
  3. Rename the created object name to “GameController”.
  4. Change the “Tag” to “GameController”.

図7.png

3. Preparation for counting the items.

3-1. Set the “Tag”.

We set the "Item" tag to "Item" object and count the number of object that has this tag.

  1. Click the “menu bar> Edit > Project Setting > Tags And Layers”
  2. Open the “Tags” menu in the “Inspector”.
  3. Open the tags by clicking the “+” button.
  4. Rename “New Tag” to “Item”.

図8.png

3-2. Set "Item" tag to "Item" object

We set the "Item" tag. “Item” tag was added to the list because registered the Item tag already.

  1. Click the "Item" object of the “Hierarchy” view.
  2. Change the “Tag” to “Item” on the “Inspector” view.
  3. Click the “Apply” button and update “Prefab”.

図9.png

3-3. Add a function to count “Item” in “GameController”.

At first, we create “GameController”.

  1. Click the “GameController” on the “Hierarchy” view.
  2. Click the “Add Component” on the “Inspector” view.
  3. Click the “NewScript” and create “GameController”.

Write the following code in the “GameController”.

Item.cs
using UnityEngine;
 using System.Collections;

 public class GameController : MonoBehaviour
 {
     public void Update ()
     {
         int count = GameObject.FindGameObjectsWithTag ("Item").Length;
     }

3-4. Display the number of remaining items.

We modify to display a number of remaining items to created UI.
At first, we think the way to connect “Text” and “GameController” Uses a way to set a reference to the ”Text” by the source code.
Create a variable for reference.

Text.cs
using UnityEngine;
 using System.Collections;

 public class GameController : MonoBehaviour
 {
     public void Update ()
     {
         int count = GameObject.FindGameObjectsWithTag ("Item").Length;
     }

Next Assign number of got Item to "Text".

Text.cs
 using UnityEngine;
 using System.Collections;

 public class GameController : MonoBehaviour
 {
     public UnityEngine.UI.Text scoreLabel;
     public void Update ()
     {
         int count = GameObject.FindGameObjectsWithTag ("Item").Length;
         scoreLabel.text = count.ToString ();
     }
 }

4. Connect "GameController" and "ScoreLabel".

Finally, we connect "GameController" and "ScoreLabel".
1. Click the “GameController” on the “Hierarchy” view.
2. Drag and drop the “Canvas> ScoreLabel” object to the “ScoreLabel”.

図10.png

Let’s start the game again. When playing the game, “the number of remaining items” is displayed in the bottom left and you can see that the remaining number decreases each time you get the item.

図11.png


ROLL-A-BALL TUTORIAL #7

$
0
0

Add end of the game

We add conditions for the end of the game.
So we should add the function.
It is the function that displays “YOU WIN” on the screen when the game player collects all items in the game.

The necessary elements to realize the function is as follows.
1. A word to mean the end of the game.
2. A judgment that finish collecting all item.

1. Make a UI of end of the game

1-1. Make label.

At first, we make a UI at end of the game.

  1. Click the “Create” button in the “Hierarchy” view.
  2. Select “UI” -> “Text”.
  3. Change the name of “Text” into “WinnerLabel” in the Inspector view.

図1.png

1-2. Set the value of the label.

Next, we set the value of the “WinnerLabel” object.
1. Select “WinnerLabel” object in “Hierarchy” view.
2. Set the value of “RectTransform” in the “Inspector” view. It is as follows.
(PosX:0, PosY:0, Width:300, Height:100)
3. Change “Text” into “YOU WIN” in the Text component.
4. Set “FontSize” into “60” in the Text component.

図2.png

図3.png

2. Set conditions for the end of the game

We set conditions in Game Controller.

The game player finishes collecting all items. It is the conditions of victory of the game.
Therefore, the game player wins if the number of items becomes Zero.

  1. Double click “GameController.cs” in Project browser to boot “Monodevelop”.
  2. Change source code. It is as follows.
GameController.cs
using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour
{
    public  UnityEngine.UI.Text scoreLabel;

    public void Update ()
    {
        int count = GameObject.FindGameObjectsWithTag ("Item").Length;
        scoreLabel.text = count.ToString ();

        if (count == 0) {
            // program when game player wins.
        }
    }
}

3. Display Label when the game finished

We display “YOU WIN” on the screen when the player completes the game.

3-1. Set referring from “GameController” to “WinnerLabel”.

  1. Open “GameController.cs” by “Monodevelop”.
  2. Change source code. It is as follows.
GameController.cs
using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour
{
    public  UnityEngine.UI.Text scoreLabel;
    public  GameObject winnerLabelObject;

    public void Update ()
    {
        int count = GameObject.FindGameObjectsWithTag ("Item").Length;
        scoreLabel.text = count.ToString ();

        if (count == 0) {
            // program when game player wins.
        }
    }
}

After change source code, return to Unity Editor.
We set referring from “GameController” to “WinnerLabel”.

  1. Select “GameController” in the “Hierarchy” view.
  2. Drag-and-drop “WinnerLabel” of “Hierarchy” view onto “winner Label Object” of the GameController component of the “Inspector” view.

図4.png

3-2. Hide object of “YOU WIN”.

We can hide the object in several ways.
This time, we choose the way to deactivate Object.

  1. Select “WinnerLabel” in the “Hierarchy” view.
  2. Uncheck the object in the “Inspector” view.

図5.png

3-3. Display Label when the game finished.

We change the status of “WinnerLabel” from inactivity to activity.
Change source code. It is as follows.

GameController.cs
using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour
{
    public  UnityEngine.UI.Text scoreLabel;
    public  GameObject winnerLabelObject;

    public void Update ()
    {
        int count = GameObject.FindGameObjectsWithTag ("Item").Length;
        scoreLabel.text = count.ToString ();

        if (count == 0) {
            // Change status of object to active.
            winnerLabelObject.SetActive (true);
        }
    }
}

4. Play the game

Let’s try to play the game.
Game player collect an item, and finally "YOU WIN" appears on the screen.

ROLL-A-BALL TUTORIAL #8

$
0
0

A barrier and restart

We try to add a new rule. New rules are as follows.
The player becomes game over when the player touches the wall where the player should not touch.

The necessary elements are as bellow.
1. Create the wall.
2. Create an event when the player touched the wall.
3. Reload a scene when the player touched the wall.

1. Create the wall

We create a wall where player should not touch.

1-1. Create the Danger Wall Prefab.

  1. Click the “Create” button in the “Hierarchy” view.
  2. Select “3D Object” -> “Cube”.
  3. Set the object name as “Danger Wall”.
  4. Set “Danger Wall” object to “Prefab” folder.

図1.png

1-2. Set the color of “Danger Wall”.

“Danger Wall” is dangerous. We want to make it look like danger.
Therefore we set the color of the wall as a “lighting wall”.

  1. Click the “Create” button in the Project Browser.
  2. Select “Material” to create “DangerWallMaterial”.
  3. Set the color in the “Inspector” view. It is as follows. (Set “Albedo” to red color, Set “Emission” to “1.5” as red color)

図2.png

  1. Drag-and-drop “DangerWallMaterial” onto “DangerWall” object in the “HIerarchy” view.
  2. Click the “Apply” button to renew the “DangerWall” prefab.

図3.png

1-3. Put “DangerWall”.

Put some “DangerWall” in the place where you want to put it.
But don’t put the wall on the item, because the player is not able to complete the game.

For example, put the wall like this…

図4.png

  1. Put three walls at the scene.
  2. Put each wall. It is as follows.
  • DangerWall 1

position (x:4, y:0.5, z:3) rotation (x:0, y:0, z:0) scale(x:10, y:1, z:1)

  • DangerWall 2

position (x:4, y:0.5, z:-4) rotation (x:0, y:0, z:0) scale(x:10, y:1, z:1)

  • DangerWall 3

position (x:-5, y:0.5, z:4) rotation (x:0, y:90, z:0) scale(x:10, y:1, z:1)

1-4. Clean up “DangerWall” and change to static.

We clean up all “DangerWall” by using the “DangerWalls” object.
And “DangerWall” objects that does not move, therefore lock a place of the wall by using “static”.

  1. Click the “Create” button in the “Hierarchy” view.
  2. Select “Create Empty” to change the name of the created object to “DangerWalls”.
  3. Drag-and-drop all “DangerWall” object onto “DangerWalls”. It makes a parent-child relation.
  4. Check the box of “static” of “DangerWalls”.

図5.png

1-5. Turn down the intensity of sunlight.

We turn down the intensity of sunlight. Because it is hard to see the wall.

  1. Select “DirectionalLight” in the “Hierarchy” view.
  2. Set the value of “Intensity” of the “Light” component in the “Inspector” view as “0.7”.

図6.png

2. Set a judgment function that touched the wall.

We create the function that reboots the scene when the player touches the wall.

  1. Select “DangerWall” in the “Hierarchy” view.
  2. Click the “Add Component” button in the “Inspector” view.
  3. Select “New Script” to create the “DangerWall” component.
  4. Click “Apply” to reflect in all prefab.

図7.png

3. Update script.

We set a call-back that receives “touched the wall” judgment.

  1. Open “DangerWall.cs” by “Monodeveop”.
  2. Change source code. It is as follows.
DangerWall.cs
using UnityEngine;
using System.Collections;

public class DangerWall : MonoBehaviour
{
    // call-back that called when player touched the object
    void OnCollisionEnter (Collision hit)
    {
        // program
    }
}

3-1. Reloading the scene.

Reloading the scene when the player touches the object that has a player tag.

  1. Open “DangerWall.cs” again by “Monodeveop”.
  2. Change source code. It is as follows.
DangerWall.cs
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;

public class DangerWall : MonoBehaviour
{
    // call-back that called when player touched the object
    void OnCollisionEnter (Collision hit)
    {
        // when tag of object that touched the wall is “Player”.
        if (hit.gameObject.CompareTag ("Player")) {
            // get the number of current scene.
            int sceneIndex = SceneManager.GetActiveScene().buildIndex;
            // Reloading the current scene.
            SceneManager.LoadScene(sceneIndex);

    }
}

Try to play the game.

※ Unity5.3 may occur a bug that becomes dark when loading the current scene.
When occurring this trouble, try the following process.
1. Select “menu” -> “Window” -> “Lighting”.
2. Uncheck the checkbox of “auto”.
3. Click the “Build” button.

Done!!!

Macで0からDjango開発環境構築

$
0
0

はじめに

この記事では、Mac環境で0からDjangoを用いた開発環境を構築する方法を説明していきます。versionはpythonは3系、Djangoは2系を使っていきます。既にインストール済のところは飛ばして、必要なところだけ参考にしてください。

環境

Mac OS Mojave 10.14.5
Homebrew 2.1.15

pyenvのインストール

pythonのversionを簡単に切り替えることができるようにしてくれるツールです。2系と3系との切り替えに便利で、ディレクトリごとにpythonのversionを切り替えることができます。
既に3系でpythonの環境構築をしている方は、読み飛ばしていただいて構いません。2系と3系を使い分けたい方は参考にしてください。

では早速インストールしていきます。Homebrewを用いて、下記コマンドでpyenvをインストールします。

$ brew install pyenv

bash_profileの編集

pyenvにPATHを通すためにbash_profileを編集します。

$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

最後にbash_profileの変更内容を適用します。

$ source ~/.bash_profile

pyenvでpythonをインストール

version切り替えを体験するために2つほどversionが違うpythonをインストールしてみます。インストールできるか確認をしたければ3つめのコマンドを利用すると一覧が確認できます。

$ pyenv install 2.7.12
$ pyenv install 3.7.4
$ pyenv install --list 

pyenvでversionを切り替えてみる

versionの切り替えをしてみます。localの場合は今いるディレクトリに、globalの場合は全体に反映されます。

$ pyenv local 2.7.12
$ pyenv global 3.7.4

ここできちんと変更が反映されているか確認するためpythonのversionを調べます。

$ python --version
Python 3.7.4

変更が反映されていれば問題ありません。
反映されていない場合、PATHの通し方によってMacに標準でインストールされているpythonが先に参照されている可能性があります。対処法が下記の記事にまとめられていますので参考にしてください。

pipのインストール

次にDjangoのインストールに必要なpipをインストールします。pipとはpythonで使われている標準的なパッケージ管理ツールです。python3.4以降では標準でpip3がインストールされていますが、今回はMacに標準でインストールされているpythonではなく、pyenvで管理しているpythonを使用するため、別途インストールが必要です。(この辺りは理解不足のため、もしかしたらインストールの必要はないかもしれません、、、)
インストール後、pipのversionを確認し、以下のようになっていればOK。

$ brew install pip
$ pip --version
pip 19.0.3 from /Users/[ユーザ名]/.pyenv/versions/3.7.4/lib/python3.7/site-packages/pip (python 3.7)

pythonの仮想環境を作成

Webアプリケーション開発をする際にいくつもの開発を進めていくとパッケージの依存関係に悩まされることがあります。 そのため、昨今のWeb開発の現場ではプロジェクト毎に仮想環境を構築します。 ここではPythonで予め用意された仮想環境構築ツールを使って仮想環境を構築します。1つ目のコマンドで仮想環境を作成し、2つ目のコマンドで仮想環境をアクティベートします。アクティベートできるとターミナルの左端に([仮想環境名])が表示されます。

$ python -m venv [仮想環境名]
$ source [仮想環境名]/bin/activate 

これでプロジェクトごとにpipのパッケージを管理できるようになります。ちなみに仮想環境から抜けるには以下のコマンドを実行してください。

$ deactivate

Djangoのインストール

やっとDjangoのインストールです。仮想環境をアクティベートした状態で、先ほどインストールしたpipを用いてDjangoの2系をインストールします。

$ pip install Django==2.2.6

Djangoがインストールできたか確認します。

$ python -m django --version
2.2.6

仮想環境内にDjangoプロジェクトを作る

仮想環境内で以下のコマンドを実行することで、Djangoプロジェクトを作成することができます。

django-admin startproject [プロジェクト名]

おわりに

これでDjangoの開発環境が構築できました!
実際にDjangoを用いてWebアプリケーションを作っていくにはもう少し準備(DBとの接続など)が必要となりますが、今回はここまでとします。

参考

サーバーレスLINEbotのためにGAS console.log+GCPで開発環境整備をした

$
0
0

要約

初心者がLINE Messaging APIをGoogle Apps Script(以下GAS)で扱おうとして、webhookのエラーやらをlogger.logで記録できなかったためにGCPに突っ込みconsole.logで見たというお話です。

初心者といいましたが、実は、20代後半になって初めてbotを動かすことに成功したというのがこの記事の副題です。また、Google Cloud Platform(以下GCP)については存在も知らない状態からのスタートになります。これまで科学計算を1台のPCでやっていただけの人です。
5時間で終わったので、皆さんも案外すぐに済むかもしれません。この記事があれば30分で済んじゃったりして。いろいろわかる皆さんは課題点を読んだ上で記事を読み、解決方法やそういった記事を残して下さると助かります。するとより良い方法の記事がQiitaに増えるでしょう。

なお、GCPの契約には無料部分はあるものの、ふとしたループなどで容易に支払いの可能性があることに了解して作業してください。ちっぽけな規模のLINEbotでも。

本題

環境

2019/10/24当時
LINE公式アカウント(個人・学生)
LINE Messaging API(フレンド50人以下フリープラン)
windows版LINE ver. 5.19.0.2020
(Android版LINEアプリ ver. 9.17.2 も傍で使用)

OS: Windows 10 Home
browser: Google Chrome 64bit (ver. 77.0.3865.120 Official Build)

GAS: standalone script
GCP: 無料トライアル12か月+300$分クーポンで初期状態、StackdriverとAPIs & Servicesの設定のみ

クレジットカードの存在(GCP契約のため)

作業の流れ

人生で初めてBotを作る人向けにある程度詳しく書いています。これは私が経験した流れとほぼ同じで、違いは常に参照した公式ドキュメントを書いていない点です。残り5時間。

LINE Messaging APIまでの下準備

LINEアカウントを持ちます。公式アカウント作成には個人アカウントとの紐づけが必要です。
LINE公式アカウントを作成します。個人アカウント側からフレンドになり、自動応答メッセージやあいさつなどの動作チェックをしてみます。この時点ではLINE Messaging APIしなくても......できるなら次は終わってます。

LINE Messaging APIの申請

申請します。プランがいくつかありますがお任せします。pushも試せる点で初心者には50人以下フレンドフリープランがいいと思いますが。
そしてLINE Official Account Managerの設定->応答設定から公式アカウントの動作をBotに切り替えます。こいつがLINEbotです。

GoogleDriveにGoogleAppsScriptアプリを導入

googleAppsScriptはSpleadsheets等から開けるものもあるが、webhook用ならば単体で開けるstandalone scriptとして始めるのがいいだろう。そのためにはアプリ自体を導入してそこから開く。
アプリ導入は、GoogleDriveの新規->その他->アプリを追加 から行える。

GAS+LINE Messaging APIの動作チェック

導入したら動作チェック。
慎重ならまずMyFunctionでlogger.log("hello GAS");でも書いてその関数をデバグ、Ctrl+Enterするとloggerに関するログが見れるのを確認しよう。
もう動いてるらしきGAS+LINE Messaging APIのコードと手順が欲しいなら

がいいでしょう。これらより古い記事はLINE@という終了したサービスについてのものが多く、紛らわしいため記載しない。コードはコピペで十分である…が、LINE Developersでロングタームのアクセストークンを得るのだけは上のサイトが画像付きでわかりやすい(私はアクセストークンの意義と存在を知らず、得るまで2時間消耗している。残り3時間)。

GASをwebhookで使ったときにlogger.logでは残らないのを学び、console.logを知る

Google Apps Scriptのデバッグ方法 をまず読む。この手順は大事だと個人的には感じる。
さて、console.logを使おうとすれば、次のような事故に出遭う…

  1. 表示->Stackdriver LoggingやStackdriver Error Reportingを選択しても訳のわからないメッセージボックスが出る
  2. いろいろやってもG Suite Developer Hub 自分のプロジェクト 辺りに飛び、エラー数くらいしかわからない

GAS Stackdriverで検索していろいろ出てくるうちで、GASでStackdriverする 2019/4/9~ 以外にはいい記事は見当たらない。読むと

GCPのプロジェクトが勝手に作成されなくなったみたい

Warning: Starting on or after April 8, 2019, the Google Cloud Platform Console won't be able to access the default GCP projects created for new Apps Script projects. Older, existing scripts may have default GCP projects that are still accessible, however. If you have a new script and require access to its GCP project from the Google Cloud Platform Console, you must use a standard GCP project.

https://developers.google.com/apps-script/guides/cloud-platform-projects#switch_to_a_different_google_cloud_platform_project

  • GCPプロジェクトを作成する
  • GASから 「リソース」「Cloud Platfome プロジェクト...」 でGCPプロジェクトの紐づけをする

正しくは、勝手に作成されなくなってのではなく、GAS作成と同時に作られるdefault GCPプロジェクトがユーザーから触れず、隠れるようになったのである。

以降、この解決のためにGCPプロジェクトを自分で用意し、移行するという作業に入ることになる。
なお、上記リンクはタグ部分が切れているため、URLを残しておく:
Google Cloud Platform Projects #switching_to_a_different_standard_gcp_project
この記事を得るまで2時間。もうあと1時間かからない。

GCPの使用申請

料金等に了解の上、申請します。
請求はされないがクレジットカードの番号を求められます。
(異様に負荷をかけた場合には請求が来るんじゃないかと思っている…が、そこは調べていません)

GCPプロジェクトの下準備

GCPに入ると、既に一つ目のプロジェクトが作成されています。好きなように名前を変更してください。そして、このプロジェクトに移行させることにします。
必要な下準備は

  1. Stackdriverの有効化
  2. APIs & Servicesの設定

です。どちらも左側のメニューから飛べます。STACKDRIVERの項目のどれかを選び、有効化します。これでStackdriver全体が有効化されます。
ついでに、GCPプロジェクトのホーム画面に戻り、Project Info.のProject Numberを控えましょう。移行時に使用します。

APIs & Services でOAuth consent screenを設定する

APIs & Servicesで必要な設定は、アプリを使用する認証画面のようです。

  1. Application nameを設定
  2. 他は気にせずSave

これだけで行けました。良いのかは不明です...

GASのdefault GCPプロジェクトから、作ったGCPプロジェクトへ移行

あとは作業です。

  1. 当該GAS画面に移動。リソース->Cloud Platform プロジェクトを選択
  2. GCPプロジェクト番号に、先ほど控えた番号を入力
  3. アプリの認証を求められるので、了解する

このとき、OAuth consent screen設定をしていないと認証できません。
余談ですが、hiddenなdefault GCPプロジェクトはGASの所有者にのみ移行権限があるようなので注意します。

GASからエラー出力画面が開けるかチェック

表示->Stackdriver LoggingやStackdriver Error Reportingを選択してGCPLogViewerのページが出れば成功。
ちなみにconsole.log自体はもちろんエラーではないのでStackdriver Loggingを選択して見てください。

以上で終わりです。調べながらやって5時間でしたので、記事を利用して30分で終わったら嬉しいなと心から思います。

参照した公式ドキュメント

LINE

なお、bot調整はLINE Official Account ManagerとLINE Divelopersがあるが、後者の方がMessaging APIを扱うのに適している。前者はMessaging API有効のbotモードでないときに効果的。

GAS

GCP

参照したその他サイト

後記

こんなに長く記事を書いたが、下の課題点は致命的過ぎて開発環境整備なんてできていないんじゃないか?と...思わなくもないです。すみません。GCPを使えるようにするのは大変だから記事にしてほしいと友人から依頼があったので、拙い構成だとしても詳細に書かせていただいた次第です。記事を書く方が時間かかってるんだが......

課題点

この組み合わせだとwebhookデバグに時間と手間がとてつもなくかかる。

  1. GASでwebアプリケーションとして導入というめんどい作業
  2. LINEでbotのwebhookURL更新
  3. LINEのやりとりしてテスト、GCP行ってログを確認

を毎回行う方法しか知らない。さらには何が送られてきたのかもわからない...わざわざconsole.log(event);って感じでStackdriver上でjsonを見ている。ばかなのか?
もう少しbotを触りたいのでどうにかしたい。少なくとも、GAS単体のデバグ時にLINEから送られてくるようなjsonデータをあらかじめ用意して突っ込む方法、あるのか?あるなら、何というのか?今こそやり方を知りたい。

編集履歴

191026:投稿

UE4で家族を錬金する。 5日目

$
0
0

UE4で彼女ができるなら、、
家族も錬金すればいいじゃない、、
その過程を記録していきたいとおもいます。

目標としてUe4のアセットである
Paragonのみなさんを家族になってもらおうと思います。

1.前日のふりかえり

長女が生まれ、家族らしくなってきた。
待ちに待った週末ゲームクリエイターとしてBPも組みたい。

00.JPG

2.長男の出産

長男はナイスガイにしたい。。

0001.JPG

[Paragon:TwinBlast]さん
アセットのサイズは2.3GBほど、ヘビーなキャラクター

https://www.youtube.com/watch?v=NKrracY0t_0

ダウンロード中にどんなキャラクターなのか研究
2丁拳銃のナイスガイ、前衛的キャラクター?
加速装置のようなロケットダッシュができる。

3.アニメーション

278アイテムも入っており、2丁拳銃アクションなら
これだ!という感じです。
ちょっとセクシーなエモーションもはいっております。
ローリング系の回避アクションこれはつかえそう。
Modも7種類+大型武器3つととても豪華!

ggg.JPG

4.あかちゃんBPの作成

週末なのでアニメーションの研究をしました。
昨日はあかちゃんを表現する際に
スケールをを0.5にしただけですが
これだとあかちゃんらしくありません。

なぜかというと頭が大きくて等身が大人のままなのです
つまり頭をでかくして4等身に近くすれば、、!
あかちゃんにより近くなるはず、、、

作成手順
1.Twinblastさんをレベル上に配置しておきます。
「拡大・縮小」を0.5としておきます。

image.png

2.Twinblastさんのアニメブループリントの
Twinblast_AnimBlueprintを複製して
「あかちゃん」という名前にします。「あかちゃん」を開きます。

t2.JPG

3.AnimGraphを開きます。最終アニメーションポーズを
 が右下あたりにあるので探します。
t4.JPG

4.ノードを追加します、右クリックしてボーンで検索して「ボーンをトランスフォーム(修正)する」を選択します。
image.png

5.「ボーンをトランスフォーム(修正)する」をクリックします。
画像のように、Bone to Modify、Scaleを設定します。
*設定ができない場合はコンパイルを一度してください。
t5.JPG

6.ノードをつなげてコンパイルすれば。。
t6.JPG

みごとな3等身に!

T7.JPG

5.参考情報

https://youtu.be/VS4poopN8mo?t=2947
↑今日のBPはこちらをみててビビビときました。
非常に為になる情報満載です。

Viewing all 21607 articles
Browse latest View live