Elixir がよかった件

昨年は いま学ぶべき第二のプログラミング言語はコレだ! 未来のために挑戦したい9つの言語とその理由 の記事がきっかけで Rust, Haskell をやって非常によかったので この流れで残りの Elixir もやってみた。

テキストはもちろんこれ 最速で知る! ElixirプログラミングとErlang/OTPの始め方【第二言語としてのElixir】

で、やってみた結果、

  • ゆるい(非純粋)関数型
    • なので末尾最適化できる
    • 関数定義にパターンマッチ、ガードが使える
    • ゆるいので変なコト書いても怒られない
  • 動的型なので気楽に書ける
  • map のリテラルがある
  • return, セミコロン書かなくていい

な点が非常によかった。 さらに新しい言語っぽく

  • repl
  • パッケージマネージャ

がちゃんとあるんで、 普段使いの言語としていい感じに使えそう。

もちろん並列処理が得意というのもいいんだけど、 それなしでもよさげ。

なので、しばらくこれ使ってみる事にする。

色々な言語で偶数自乗和 その2

TL;DR

Haskell ならパイプライン演算子を自分で定義できるよ

java8

import java.util.stream.IntStream;

public class Main {
    public static Integer evenSquareSum(Integer n) {
        return IntStream.range(1, n)
            .filter(n1 -> n1 % 2 == 0) // variable n is already defined in method evenSquareSum(Integer) と出るので変数名を変更。引数と同じ変数名は使えないみたい
            .map(n1 -> n1 * n1)
            .reduce(0, (acc, n1) -> acc + n1)
            ;
    }

    public static void main(String[] args) throws Exception {
        Integer result = evenSquareSum(10);
        System.out.println(result);
    }
}

ちょっと見ない間にだいぶマシになった印象。 でも SIer とかだとバージョンアップできない所も多いんだろうな…

kotlin

fun main(args: Array<String>) {
    val result = evenSquareSum(10)
    println(result)
}

fun evenSquareSum(n: Int): Int {
    return (1..n)
        .filter{
            n -> n % 2 == 0
        }.map{
            n -> n * n
        }.fold(0) {
            acc, n -> acc + n
        }
}

よいです。

swift

func evenSquareSum(n: Int) -> Int {
    return (1...n)
        .filter { $0 % 2 == 0 }
        .map { $0 * $0 }
        .reduce(0) { $0 + $1 }
}

let result = evenSquareSum(n: 10)
print(result)

クロージャの省略記法いいね。

haskell

evenSquareSum n =
  sum . map (\n -> n * n) . filter even $ [1..n]

{- これでも OK
evenSquareSum n =
  foldl (+) 0 $ map (^2) $ filter even [1..n]
-}

main = do
    let result = evenSquareSum 10
    print result

やっぱり右からになるのね と思ったら、自分でパイプライン演算子が定義できるみたい via * HaskellでElixirのようなパイプラインで記述したいとき - Qiita * Hakellでパイプライン演算子

(|>) :: a -> (a -> b) -> b
(|>) a f = f a
-- a |> f = f a

evenSquareSum n =
  [1..n]
    |> filter even
    |> map (\n -> n * n)
    |> foldl (+) 0
main = do
    let result = evenSquareSum 10
    print result

すごい

色々な言語で偶数自乗和

TL;DR

このごろ新しく言語を見る時、Hello world の次くらいに偶数自乗和を 作る関数を定義してる。Ruby で書くとこんな感じ。

def even_square_sum(n)
    (1..n)
        .select {|n| n % 2 == 0} 
        .map {|n| n * n} 
        .inject {|acc, n| n + acc}
end
puts(even_square_sum(10)) # => 220 が表示されると正解

いくつかルールがあって

  • リストの内包表記は使わない
  • range 的なのがあれば使う
  • 最後の合計はなるべく畳み込み(reduce, fold系) を使う

これをやると

  • 無名関数の定義のしかた
  • 関数の定義のしかた
  • 関数の呼び出しかた
  • 基本的な高階関数の使い方

が分かるので、なかなか気にいってる。 では今まで作ったのを紹介してみる。

Rust

fn even_square_sum(n: isize) -> isize {
    (1..n)
        .filter(|n| n % 2 == 0)
        .map(|n| n * n)
        .fold(0, |acc, x| acc + x)
}

fn main() {
    let result = even_square_sum(10);
    println!("{}", result);
}

普通かな。 でもこの書き方をゼロコストでやってくれるのはいいね。

Common Lisp

(defun range (from to &optional (res '()))
    (if (eq from to) (cons to res)
        (range from (1- to) (cons to res))))

(defun even-square-sum (n)
    (reduce #'+
        (mapcar #'(lambda (n) (* n n))
            (remove-if-not #'evenp (range 1 n)))))

(setq result (even-square-sum 10))
(print result)

range がなかったので自作してみた。末尾再帰ではないので、ヒマがあったら変えたい。 適用する順番が頭で考えるのと逆順になってしまうので読みづらい。 マクロ作ればパイプライン的な事もやれそうだけど。

TypeScript

function evenSquareSum(n: number): number {
    const numList: number[] = Array.from(Array(n).keys());
    return numList
        .filter((n) => n % 2 == 0)
        .map((n) => n * n)
        .reduce((acc, n) => acc + n);
}
const result = evenSquareSum(10)
console.log(result);

普通かな。range がないので、Array.from() を使ったけどやはり気持ち悪い。

Elixir

evenSquareSum = fn (n) ->
    (1..n)
        |> Enum.filter(fn n -> rem(n, 2) == 0 end)
        |> Enum.map(fn x -> n * n end)
        |> Enum.reduce(0, fn n, acc -> n + acc end)
end
result = evenSquareSum(10)
IO.puts(result)

パイプライン演算子(|>)いいね。 リスト操作以外にも使えそうだし、 もっと他の言語にも取り入れてもらいたい。

import Enum
1..10 |> filter(&rem(&1, 2) == 0) |> map(&(&1 * &1)) |> reduce(&(&1 + &2))  

git rebase -i をちょっと楽にするエイリアス

いつもいつも git rebase -i HEAD^^ を打つのが めんどくさいので作ってみました。

使用例

  • git irebase
    • → git rebase -i HEAD~2
  • git irebase 5
    • → git rebase -i HEAD~5
    • 数字をつけるとその数さかのぼる
  • git irebase ^^^
    • → git rebase -i HEAD^^^
    • ^ や ~ だけの場合、 HEAD からさかのぼる
  • git irebase 2 develop
    • →git rebase -i HEAD~2 develop
    • ブランチ指定も可

詳しくはソースを参照の事。 以下を git-irebase として PATH の通ったディレクトリに置いて使います。 https://github.com/yosugi/git-irebase にも上げておいたので、 お好きな方をどうぞ。

#!/usr/bin/env perl
use strict;
use warnings;

sub main {
    my ($upstream, $branch) = @_;

    $upstream = 2 unless ($upstream);
    $branch = "" unless ($branch);

    if ($upstream =~ /^[0-9]+$/) {
        $upstream = "HEAD~$upstream";
    } elsif ($upstream =~ /^[0-9^~]+$/) {
        $upstream = "HEAD$upstream";
    }

    exec "git rebase -i $upstream $branch";
}

main(@ARGV);

__END__

=head1 NAME

git-irebase - alias for git rebase -i

=head1 SYNOPSIS

  $ git irebase [<upstream>] [<branch>]

=head1 DESCRIPTION

  $ git clone https://github.com/yosugi/git-irebase.git
  $ export PATH=./git-irebase:$PATH
  $ git irebase

=head1 AUTHOR

yosugi

=head1 LICENSE

MIT license (http://opensource.org/licenses/mit-license.php)

=cut

github のリポジトリ構造は https://github.com/kyanny/git-copy を参考にさせて もらいました。感謝です。

MODx の管理画面ツールバーにボタンを追加する

MODx の管理画面をカスタマイズした時のメモです。 最後の doLayout() が分からなくてハマったので注意。

MODx.on('ready', function() {

    var buttons = [];
    buttons.push({
        text: 'hello',
        handler: function () {
            alert('hello'); // 実行させたい処理をここに書く
        }
    });

    var toolBar = Ext.getCmp('modx-action-buttons');

    // この toolBar は Ext.Toolbar クラスなので対応するメソッドが使えます。
    // http://extdocs.xenophy.com/?class=Ext.Toolbar

    toolBar.addButton(buttons); // 最後に追加
    // toolBar.insertButton(3, buttons); // 3 番目に追加

    toolBar.doLayout(); // 描画し直す
}

vim のインサートモードで行頭をトグルする

vim を使ってて、emacs みたいに C-a で行頭と空白以外の最初の文字を トグルしたかったので作ってみました。

function! ToggleBol()
    let col = virtcol('.')
    let cmd = (col == 1) ? '^' : '0'
    execute "normal! " . cmd
endfunction
inoremap <C-a> <C-o>:call ToggleBol()<CR>

コメントアウトする時とかに便利かも。

追記

Qiitaのコメント で教えてもらったやり方のがよさそうなので、こっちにも書いときます。

inoremap <expr> <C-a>
      \ search('^\s\s*\%#', 'bcn') ? "\<C-o>0" : "\<C-o>^"

search とか初めて知ったよ。

twig で配列の数をカウントする

ちょっと検索しただけでは分からなかったので。 ほとんど参考サイトのコピペですが。

{% if my_list|length > 10 %}
    ...
{% endif %}