カリー化された関数

qiitaの週間ランキング?の上位に、カリー化された関数の話が出ていたけど、分かりにくいなぁと思ったので、自分なりに記事を書いてみる。

ちなみにカリー化された関数は英語訳するとcurried functionになる。

Standard ML of New Jersey という言語がある。その言語は、メジャーな言語と比べるとなんか癖が強いと思うけど、言語として、いろんな特徴が実装されているように思える。その 1 つにカリー化がある。

smlnjをインストールすると、インタープリタが実行できるようになる。

% sml
Standard ML of New Jersey v110.85 [built: Sat Dec 22 16:51:02 2018]
- val a: int = 2 + 3;
val a = 5 : int

例えばこんな風に。

関数の定義は、

- fun add a b: int = a + b;

こういう構文になる。

呼び出しはこう。

- add 2 4;
val it = 6 : int

ところで、smlnjは、静的な型付言語で、関数を定義すると、型が出力される。

- fun increment (a:int) : int = a+1;
val increment = fn : int -> int

この場合、incrementという変数に、ラムダ式を代入したような、表記が出力されており、int型の引数を渡すとint型の値が帰ってくるようなのが書かれているのがわかると思う。

引数が増えると、どうなるのか予想して見て欲しい。 最初、僕は

- fun add a b: int = a + b;
val add = fn : int, int -> int

こうかと思ってた。でも、違った。

- fun add a b: int = a + b;
val add = fn : int -> int -> int

実際はこうだった。 int -> int -> int は、わかりやすく書くと、int -> (int -> int)のことで、これは、実際に、1 つの引数でも呼べることを意味している。

- val add2 = add 3;
val add2 = fn : int -> int

これを宣言しておくと、

- add2 5;
val it = 8 : int
- add2 19;
val it = 22 : int

こんな風な呼び出しができるようになる。つまり、部分適用ができるようになる。

もちろん、僕が最初に思ったような書き方もできる。

- fun add (a,b) = a+b;
val add = fn : int * int -> int

タプル(tuple)を使用すると最初に思ったような関数を宣言することができる。

こんな風に、部分的な動作をする関数を返すことができる関数をキャリー化された関数というらしい。

正確には、wikiとかをみると、写像とかの詳しい話が出ていて、部分適用が行いやすくなるという程度にとどまっている。

wikiを読むと、カリー化と部分適用を混同するなよって書いてある。

部分適用は、あくまで、add(3)でも呼べるようにすることで、カリー化は、add(x)とした時の動作を規定することって書いてある(ように感じた)。

pythonでのファイルサイズの取得

os.path.getsize(path)を使えばいいらしい。

ファイルサイズ出力のスクリプト作った。

""" print_size.py """
import os
import sys

if __name__ == '__main__':
    try:
        size = os.path.getsize(sys.argv[1])
        f = ""
        if 10**3 <= size < 10**6:
            f = f"{size//10**3: 4} kB"
        elif 10**6 <= size < 10**9:
            f = f"{size//10**6: 4} MB"
        elif 10**9 <= size < 10**12:
            f = f"{size//10**9: 4} GB"
        elif 10**12 <= size < 10**15:
            f = f"{size//10**12: 4} TB"
        else:
            f = f"{size: 4} B"
        print(f)
    except OSError:
        print("The file doesn't exit.", file=sys.stderr)
    except:
        print("USAGE: print_size.py path", file=sys.stderr)
% for i in `ls`;                                                                      
for> python ../print_size.py ${i}
 640 B
  47 B
  79 B
  11 kB
  21 kB
   1 MB
   1 MB
   1 MB
  31 kB
   3 MB
  22 kB
   1 MB
   3 MB
   6 MB
 597 kB

すぐ作った割に使えるので、載せずにはいられなかったw

smlnjの中値演算子のやつ

タイガーブックやってたら、中値演算子を定義するものが見つかったので、試してみた。

Standard ML of New Jersey v110.85 [built: Sat Dec 22 16:51:02 2018]
- (* 演算子 plus を定義 *)
- infix 6 plus;
infix 6 plus
- (* 演算子 plus2 を定義 *)
- infix 8 plus2;
infix 8 plus2
- (* 演算子の振る舞いの定義 *)
- fun x plus y = x + y;
val plus = fn : int * int -> int
- fun x plus2 y = x + y;
val plus2 = fn : int * int -> int
- 2 * 3 plus 4;
val it = 10 : int
- 2 * 3 plus2 4;
val it = 14 : int

plus2は*(結合度6)よりも高く設定してあるので、2 * 3 plus2 4 は2 * (3 + 4)として計算される。infixは左結合の演算子の定義らしいので、右結合の場合は、infixrを使えばいいみたい。右結合というのは、例えば、a = b = c;という文があった場合、多くの言語でb = cが先に実行されるでしょう?それ。

- (* 仮の代入演算子 equal の設定 *);
- infixr 4 equal;
infixr 4 equal
- fun a equal b = (
= print (a^"に"^b^"を代入したとする\n");
= b);
- "a" equal "b" equal "c" equal "3";
cに3を代入したとする
bに3を代入したとする
aに3を代入したとする
val it = "3" : string
- (* 左結合バージョン *)
- infix 4 equal2;
infix 4 equal2
- fun x equal2 y = (
= print (x^"から"^y^"\n");
= x);
val equal2 = fn : string * string -> string
- "2" equal2 "a" equal2 "b";
2からa
2からb
val it = "2" : string

ということになる。

1ss178の考察

定本トランジスタ回路の設計をすすめる。
1ss176(ショットキーバリアダイオード)の代替品を探した。
google先生に頼んだら秋月の1ss178が見つかった。

176~178は同じ?っぽい。違うのは最大定格。使用の際は、圧倒的に最大定格を下回っているので、大丈夫。

If-Vf図を見ると、100mAでVfが0.9V。本に書いてあるのは0.01mAなので、10^-2A@25℃であるので、Vfは0.4V?。まぁダイオードを入れないよりかはマシかなとは思う。これは実験してみたい項目だなぁと思った。
逆電流も考える必要は特にない。今回の回路は。

今回のダイオードは、電圧を無理やり下げるために用いている。

ちょっとしたメモでした。

poj3280 cheapest palindrome

区間DPらしい。 蟻本の練習問題。 基本的なDPって書いてあったのに、できなかったけど()

普通に文字列周りの問題が壊滅的にできないと思った。全然できんし。

これがわかってたらという事柄をあげる

  • 全探索の方向
  • 最小条件のクリア

eagletmt.github.io

解答はこの方のを見れば、かなりわかりやすいと思う。

全探索の方向

"abcdef"という文字列があった時、この問題の場合は、c, bc, cd, bcd, abcd, bcde, abcdeっていうのを先頭からやっていく感じだった。わかんなかったな〜

最小条件のクリア

これは、リンク先の解説に書いてあるんだけど、"abcba"というのがあって、cをみたとき、bcを回文にするには、cの左を消すか、bを右に新たに付け足すという動作をすることになって、結局それのどちらがコストが小さいのかというと付け足すコストと消すコストの小さい方になる、このことは、具体的にメモしないとわかんなかったな。もちろんすでに左右対称ならコストは0になる。

区間DPできるようになりテェな

djangoの時間まわり

以前に、djangoのコードからローカライズされた時間を取得する方法をやったけど、それを含めて整理する。

まず、プロジェクトを立ち上げた時、時間まわりの設定は、

TIME_ZONE = 'UTC'
USE_TZ = True

になっている。

djangoのコード内で、日付時間を取得する場合は、以下の二つ?

  • datetimeモジュール
  • django.utils.timezoneモジュール

この状態で、とりあえず今日の日付と時間を取るならば、

>>> from django.utils import timezone
>>> timezone.now()
datetime.datetime(2019, 3, 13, 19, 45, 1, 21127, tzinfo=<UTC>)
>>> from datetime import datetime
>>> datetime.now()
datetime.datetime(2019, 3, 13, 19, 45, 15, 660571)

になる。この場合は、TIME_ZONEとUSE_TZの影響で同じ出力になった。

次に、

TIME_ZONE = 'Asia/Tokyo'

に変えると

>>> from django.utils import timezone
>>> print(timezone.now())
2019-03-13 19:43:00.744599+00:00
>>> from datetime import datetime
>>> print(datetime.today())
2019-03-14 04:43:23.253193

datetimeモジュールだけTIME_ZONEの影響を受ける。

だから、基本的に、時間取得なら設定を変えてdatetimeモジュールを使用する?

じゃあ、timezoneは何に使うんだよっていう話になる。

これは、憶測だけど、憶測だけど、憶測だけど、テンプレートを通して取得した場合にのみ使用するのかもしれない。 上のは、manage.pyのshell。

タイガーブック(3)

ml-lexのレキサーを書いていた。

github.com

この方のがとてもわかりやすいと思う。 これの 2 章。

tiger.lexを書く。

%s COMMENT

正確には%stateらしい。

COMMENTという状態をあらかじめ定義しておく。

var type function break of end in nil let
do to for while else then if array
:= | & >= > <= < <> = / * - + { } ( ) [ ] . , ; :
abcdefg
12345
"ABCDEFG"
/* comment has started */

こんな感じのtiger(作るプログラミング言語の名前)のソースコードらしきものを用意しておく。

tiger.lexを修正して、

% sml
Standard ML of New Jersey v110.85 [built: Sat Dec 22 16:51:02 2018]
- CM.make "sources.cm";
略
- Parse.parse "test.tig";
VAR   2
TYPE   6
FUNCTION   11
BREAK   20
OF   26
END   29
IN   33
NIL   36
LET   40
DO   44
TO   47
FOR   50
WHILE   54
ELSE   60
THEN   65
IF   70
ARRAY   73
ASSIGN   80
OR   83
AND   85
GE   87
GT   90
LE   92
LT   95
NEQ   97
EQ   100
DIVIDE   102
TIMES   104
MINUS   106
PLUS   108
LBRACE   110
RBRACE   112
LPAREN   114
RPAREN   116
LBRACK   118
RBRACK   120
DOT   122
COMMA   124
SEMICOLON   126
COLON   128
ID(abcdefg)     130
INT(12345)   138
STRING("ABCDEFG")     144
skipping comment
skipping comment c
skipping comment o
skipping comment m
skipping comment m
skipping comment e
skipping comment n
skipping comment t
skipping comment
skipping comment h
skipping comment a
skipping comment s
skipping comment
skipping comment s
skipping comment t
skipping comment a
skipping comment r
skipping comment t
skipping comment e
skipping comment d
skipping comment
EOF   179
val it = () : unit

これで字句解析ができてそうなことを確認できた。 tokens.smlに関数は、定義されているので、tiger.lexを完成させればいいだけ。