Haskellでの配列についてのページ

Haskellで初めて配列を扱う場合にとてもわかりやすいページ。
404 Not Found

Haskellの配列はなかなか使い方が頭に染み込まなかったので、こういうページで解説してくれるとありがたい。

ITProのページはシンタックスハイライトが効いて欲しいのと、一行のコードの折り返しをしてくれればかなり見やすくなるのにといつも思う。

選択範囲のセルを任意の文字で埋める

こんなのがあった時に、

左上から、右下まで選択して、実行すると


こんな風に埋めてくれるようなVBA

Sub test()
    ' この場合、セルが空白なら0で埋める処理になる
    Call fillXtoY("", 0)
End Sub
 
Sub fillXtoY(x, y)
    For i = Selection(1).Row To Selection(Selection.Count).Row
       For j = Selection(1).Column To Selection(Selection.Count).Column
            If Cells(i, j) = x Then
                Cells(i, j) = y
            End If
        Next
    Next
End Sub

https://gist.github.com/pogin503/5150808
VBAだとサブルーチンはCallで呼ぶといいみたい。

追記 2017/03/22
もっと簡単な書き方があるっぽい。

Sub test()
    ' この場合、セルが空白なら0で埋める
    Call fillXtoY("", 0)
End Sub
 
Sub fillXtoY(x, y)
    Dim i As Long, j As Long
    With Selection
        For i = 1 To .Rows.Count
            For j = 1 To .Columns.Count
                If .Cells(i, j) = x Then
                    .Cells(i, j) = y 
                End If
            Next
        Next
    End With
End Sub

今日の見かけたリポジトリ

コードリーディングを全然してないのでメモのために見つけたリポジトリを書いていこうと思う。
io-streamライブラリ。今日1.0がリリースされた。
io-streamについてのtanakhさんのツイート。

GitHub - snapframework/io-streams: Simple, composable, and easy-to-use stream I/O for Haskell

io-streamのhttp関連のやつ。http-conduitとどっちがいいのかはわからない。
GitHub - afcowie/http-streams: Haskell HTTP client library for use with io-streams

C言語をパースするパーサー
GitHub - mchakravarty/language-c-quote

GHCGithubリポジトリ
GitHub - ghc/ghc: Mirror of the Glasgow Haskell Compiler. Patches are best submitted to GHC's Phabricator (https://phabricator.haskell.org/), bugs and feature-requests are best filed to GHC's Trac (https://ghc.haskell.org/trac/ghc), or sent to the mailing list (ghc-devs@haskell.org). First time contributors are encouraged to get started by just sending a Pull Request.

moshをさくらVPSで使う(Ubuntu12.04)

Moshという端末をリモートで操作するSSHの代替となるソフトウェアをちょっと使ってみたかったのでインストールをしてみた。

Moshは通信環境が不安定環境、例えばモバイル環境でも安定したリモート接続ができるようになるとのこと。さらにSSHよりも高速に動く。パソコンをスリープ状態にして復帰した時にリモートの接続が切れない、早くコマンドを打ったとしてもスクリーンが固まったりしないというのは便利なのです。

設定

まずSSHの設定がいるようなので、公開鍵とかを作る。

ホスト側で

ssh-keygen -t rsa "example@example.com"
#->このあとパス設定とかいろいろでる

作ったら安全のためscpを使ってリモート側に送る。

scp -2 id_rsa.pub username@hostname:scp_id_rsa.pub

### scp [オプション][転送したいファイル名][転送先のパス]
### [転送先のパス] は [username]@[hostname]:[path]
### [path]はディレクトリを省略するとホームディレクトリを示す

次はリモート側(Ubuntu)で

mkdir -p ~/.ssh 
chmod 700 ~/.ssh
cat scp_id_rsa.pub >> ~/.ssh/authorized_key

サーバーで鍵の追加が終わったらUbuntuMoshのインストールをしておく。

sudo apt-get install mosh

ポートの開放も必要なのでしておく。

sudo ufw allow 60000:61000/udp

これが終わったらホスト側で、Moshをインストールする。自分の環境がMacなので、Macbrewを使った設定をする。
Macの場合のインストールで気をつけないといけないのがbrew install moshとやるとSchemeインタプリタMoshがインストールされるので気をつけてインストールする。

# × まちがい
# brew install mosh

# ◯ せいかい
brew install mobile-shell

間違えてインストールした場合は

brew uninstall mosh

でアンインストールする。

Schemeインタプリタmoshを先にインストールしてしまうとアンインストールしても

mosh 1.2.3 already installed, it's just not linked

とか出てしまって、関連付けがうまくいかなかった。失敗してる場合は

brew link mobile-shell

とやって、関連付けを直す。

インストールが終わったら

mosh username@hostname

で接続できるみたい。

でも...

mosh requires a UTF-8 locale.
Connection to hostname closed.
/usr/local/bin/mosh: Did not find mosh server startup message.

( ゚д゚)………

はいはいlocaleが間違っているんですねっと

調べるためにUbuntu側でlocaleと打ってみる。

$ locale
↓
LANG=C
LANGUAGE=
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=

はいUTF-8になってないと...。

utf-8にするために、検索で調べてみるとlanguage-pack-jaとかインストールすれば設定できるみたい。
Ubuntu側で、

sudo apt-get install language-pack-ja
export LANG=ja_JP.UTF-8
sudo update-locale LANG=ja_JP.UTF-8

/etc/ssh_config の PermitUserEnvironmentは見つけきれなかったのでやらなかった。

ロケール設定が終わったら、Mac側でmoshのコマンドを打つ。

mosh pogin@hostname
# -> [pogin@hostname ~]

セキュリティが心配な場合、接続ポートを限定したほうがよい。ポートを指定する場合は

mosh -p 60100 username@hostname

で特定ポートでmoshを使えるようになる。

(追記2013/3/5):他にポート指定のオプションのやり方は種類があるので、公式サイトのUsageのところを見れば良い。(どうもmoshファイアウォールの設定に影響されやすいっぽい)

これでmoshが使えるようになった。これならさくらのサイト上のリモートコンソールを使わずにシェルを使うことができる。なので非常に楽かつ、接続が切れても問題ないのが嬉しい。

SSHの設定とかはドットインストールという3分動画でマスターできる初心者向けプログラミング学習サイトでわかりやすく説明してくれてる。

ここでは他に、Apache, PHP,ファイアウォールなどの設定の講座をしてくれているのでスタートにはとても便利なものになってる。自分もドットインストールのビデオを見てPHPを動かせるところまでやってみようと思う。
http://dotinstall.com/lessons/basic_sakura_vps

yesodで詰まったところのメモ

yesodでちょっとエラーで詰まったことのメモ。

追記2013.7.5 Yesodのバージョンは1.1ぐらいだった気がする。

エラー1

Handler/Blog.hs:17:9:    No instance for (RenderMessage master0 FormMessage)
      arising from a use of `area'
    Possible fix:
      add an instance declaration for (RenderMessage master0 FormMessage)
    In the second argument of `(<$>)', namely
      `areq textField "Title" Nothing'
    In the first argument of `(<*>)', namely
      `Article <$> areq textField "Title" Nothing'
    In the second argument of `($)', namely
      `Article <$> areq textField "Title" Nothing
       <*> areq nicHtmlField "Content" Nothing'

Handler/Blog.hs:18:16:
    Couldn't match expected type `Text' with actual type `Html'
    Expected type: Field sub0 master0 Text
      Actual type: Field sub0 master0 Html
    In the first argument of `areq', namely `nicHtmlField'
    In the second argument of `(<*>)', namely
      `areq nicHtmlField "Content" Nothing'

areq でエラーがなぜか出る...。

modelとformの引数が違う可能性がある

config/modelsのモデルを見てみる。

-- config/models

Article
  name Text
  title Text
  content Html
  createdAt UTCTime default=CURRENT_TIMESTAMP
  deriving

見てみると、name, title, content, createdAtの4つのデータがArticleには必要だとわかる。

モデルと一致しない間違ったentryForm

-- Handler/Blog.hs
entryForm :: Form Article
entryForm = renderDivs $ Article
    <$> areq   textField "Title" Nothing
    <*> areq   nicHtmlField "Content" Nothing

これはtitleとcontentの2つしか作っていないということになる。
モデルと一致したentryForm

-- Handler/Blog.hs
entryForm :: Form Article
entryForm = renderDivs $ Article
    <$> areq   textField "Name"  Nothing
    <*> areq   textField "Title" Nothing
    <*> areq   nicHtmlField "Content" Nothing
    <*> aformM (liftIO getCurrentTime)

こっちはname, title, content, createdAtの4つに対応する形でコードが書かれているのでモデルに一致している。

http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/
いろいろなサイトのやつを見ながらコピペで作ってたら変なエラーを起こしてしまった。できたら一つのサイトのコピペで完了させたかったのだけれど、うまく動かなかったので外のサイトのコピペで動かしてたらこんなエラーが...。

エラー2

ちゃんとgetFooRとpostFooRを書いてるのにこの2つが無いとか言われる。↓
Application.hsにHandler.Fooを入れ忘れてるかもしれない。or
HogeHoge.cabalファイルにHandler.Fooを書き忘れてるかも。
なので両方を確認して、入れてなかったらそれぞれにHandler.Fooを入れる。

Application.hsにはimportを加える。

-- Application.hs
import Data.Foo

HogeHoge.cabalには、exposed-modulesにHnadler.Fooを入れとく。

-- HogeHoge.cabal
Flag library-only
    Description:   Build for use with "yesod devel"
    Default:       False

library
    exposed-modules: Application
                     ....
                     Handelr.Foo    -- ←ここに入れる

    if flag(dev) || flag(library-only)
        cpp-options:   -DDEVELOPMENT
        ghc-options:   -Wall -O0
    else
        ghc-options:   -Wall -O2

エラー3

Handler.Mirrorを作ってる時のこと。widgetのmirrorがないとか言われる。

Exception when trying to run compile-time code:
      Called widgetFileReload on "mirror", but no template were found.
      Code: widgetFile "mirror"
    In a stmt of a 'do' block: $(widgetFile "mirror")
    In the second argument of `($)', namely
      `do { $(widgetFile "mirror") }'
    In a stmt of a 'do' block:
      defaultLayout $ do { $(widgetFile "mirror") }

widgetファイル(この場合mirror.hamlet)を定義してない。なので、templates/にmirror.hamletを作る。

シェルでifの結果を一行で確認する方法

最近シェルでif文を一行(oneliner)でささっと確認したいことがあった。ググるけど、いろいろ情報が分散してたみたいなので分かりやすそうなのを書いておく。

例として、いくつか出してみる。

#正規表現 使用しているOSが64bitかどうか
[[ `uname -m` =~ x86_64 ]]; echo $?
# 0(true) or 1(false)

#数値の比較
[[ `expr 1 + 3` -eq 4]]; echo $?
# -> 0

これで0の時に真で、1の時が偽になるので、簡単に実行結果の確認ができる。1行で書けるとファイルを作らずに実行結果を確認ができるので良い。

ちなみにexprって一体なんだろうという人もいるかもしれませんが、shell scirptでは1+3は文字列になってしまうので、exprで数値計算として解釈させないといけないです。

端末の方でif-else、if-elif-elseの確認もできる。

#一行if-else (if-elseなし)
[[ `uname -m` =~ x86_64  ]] && echo "match" || echo "unmatch"

#一行if-else(if-elseあり)
if [[ `uname -m` =~ x86_64  ]];then  echo "match"; else echo "unmatch"; fi

# 一行if-elif-else
if [[ `uname -m` =~ x86_64 ]]; then echo "x86_64"; elif [[ `uname -m` =~ i686 ]]; then echo "i686"; else echo "unmatch"; fi

ところで、1行のことはone line、single lineと二つ呼び方があるのだけど、どっちが正解なのだろう。
調べてみると

one line 一行
single line 単一行、単線、一行

どっちもかわらないみたい。好きな方を使えばいいということなんだろうか。

今回のことで学んだことは参考リンクの方にいろいろ載ってる。$? とか [ ] と [ [ ] ]の違いとか。

gitのpost-receiveフックを使ってみる(全部ローカル)

全部ローカルで動くようなパターンをやってみた。post-receiveの記事は、サーバーとかに対してのやり方は書いてあるけど、ローカルでやる方法は見当たらなかったので書いてみた。

どんな動きをするかテストをしてみる。

やって見る内容は、この3つのリポジトリで流れを確認する。

~/foo/test          # ローカルリポジトリ
~/foo/repo.git    # ベアリポジトリ
~/foo/receive     # post-receiveが働いたときにデプロイされるディレクトリ

テスト用リポジトリを作る (~/foo/test )

まず
~/foo/testから作る。これはpost-receiveを動かすためのディレクトリになる。

cd ~/foo/
mkdir test
cd test/
git init
touch test.txt
echo "test" >> test.txt
git add . && git commit -m "test commit"
>> 出力先に上書き保存をする
&& &&の左のコマンドが成功したら右のコマンドを実行する

こんな風にやってまずはテスト用のリポジトリを作る。

テスト用リモートを作る (~/foo/repo.git)

次に ~/foo/repo.git というリモートを作る。これは ~/foo/test からのpushを受けるためのディレクトリになる。

cd ~/foo/
mkdir repo.git
cd repo.git
git init --bare   #リモートリポジトリを作るためにbareリポジトリを作る

repo.gitというリモートを作ったら、~/foo/test リポジトリに移動して push する

cd ~/foo/test
git push ~/foo/repo.git master

自動でpushされる場所を作る (~/foo/receive)

最後は ~/foo/receive というディレクトリを作る。これはフックの時にpushするためのリポジトリになる。

cd ~/foo/
git clone repo.git receive   # cloneのときreceiveというディレクトリ名でクローンする

フックの設定をする(~/foo/repo.git)

recieveを作ったらフックを使うための準備をする。場所は~/foo/repo.git/hooksのところのpost-receiveを使う。

cd repo.git/hooks/

emacsとかvimとかnanoとかgeditなどなどの編集できるものを使う。

nano post-receive

編集画面に入ったら下のコードをコピペする。ペーストは端末ならCtrl + Shift + v でできるはず。だめなら右クリックで。
GUIの方ならエディタごとにペーストは異なる。

#!/bin/sh

# . /home/username/repo.git/hooks/post-receive
echo "test post-receive"
pwd # post-receiveが実行されるときはrepo.git/にいる
cd ~/foo/receive # --git-dirを設定するために移動する
pwd
git --git-dir=.git pull ../repo.git master
pwd カレントディレクトリを出力する

最後に実行権限を付けないとだめなのでchmodを実行しておく。

chmod +x post-receive

実行できるかの確認

ここまでちゃんとできてると、下のコマンドを実行するとうまいことローカルだけでpost-receiveが動くようになる。

cd ~/foo/test
echo "test" >> test.txt && git add . && git commit -m "test commit" && git push ../repo.git/ master

実行結果はだいたいこんなかんじに成る

[pogin@localhost ~]
$ cd foo/test/
[pogin@localhost test]
$ echo "test" >> test.txt && git add . && git commit -m "test commit" && git push ../repo.git/ master
[master 88427c1] test commit
 1 file changed, 1 insertion(+)
Counting objects: 5, done.
Writing objects: 100% (3/3), 256 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: test post-receive
remote: /home/pogin/foo/repo.git
remote: /home/pogin/foo/receive
remote: From ../repo
remote:  * branch            master     -> FETCH_HEAD
remote: Updating 6623237..88427c1
remote: Fast-forward
remote:  test.txt | 1 +
remote:  1 file changed, 1 insertion(+)
To ../repo.git/
   6623237..88427c1  master -> master

これで、~/foo/repo.gitにpushしたときにpost-receive-hookが作動して、~/foo/receive にデプロイ?されるようになる。

あまり需要がないかもしれないけど、サーバーを持ってなくて、とりあえずローカルにサイトを構築していじる必要のないサイトを再現しておくときにこの手法が役に立つかもしれない。

実行用のshell scriptも作ってみたんで早く確認したい人はどうぞ。

追記2013.7.20

日本語がおかしかったり、説明不足のところを少し追記。