カレー・ブルストの作り方
雨に唄えばおじさんと揚げ玉ビーチ
╰( ´◔ ω ◔ `)╯ またまた Swiff の話だ
╰( ´◔ ω ◔ `)╯ 多分な
換気扇の空、オリーブオイルの海、揚げ玉の海岸。
雨に唄えばおじさんは自分が厄介な場所に来てしまったことを悟った。
ということで、以下のコードはコンパイルエラーになる(はず):
let hoge : Nil = nil; // Nil のみの型を持つ変数の宣言はコンパイルエラーになる。 let piyo : int? = nil; // Nil 許容型の変数に nil を初期値として設定するとコンパイルエラーになる。 let fuga : int = nil; // 整数型の変数に nil を初期値として設定するとコンパイルエラーになる。
hoge
の方は、やっても意味がない宣言だと思う。nil
しか設定できないし……。
piyo
の方は、null 排斥運動におけるコンパイルエラー。
多くの場合、最初に null
が入っているから NullReferenceException
が送出されるので、
null
を初期値として設定しないようにすれば多くの場合 NullReferencException
を退けられるだろうという考えらしい。
Wikipedia では「安全性のために」としか書いてないけど。
fuga
の場合はそりゃそーだよなって感じ。int
型の変数に nil
は設定できない。
でも、こっちはどうだろう:
let hage = getHage();
getHage()
がこうなっていると:
def getHage() : int? { if true { return nil; } 42; }
hage
には nil
が設定される。
こういう場合は、「nil
しか返ってこなさそうですよ」って Warning を表示した方が良いんだろうか?
っていうか、こういう場合、Visual Studio*1 では到達不可能なコードなんちゃらあるって言われるよな………。
こういう場合は、やっぱりなんともならないよなぁ:
let hyoga = int.parse( "X" );
まあ、関数の戻り値の nil
はいいことにしようっていうか、リテラルとしての nil
を設定するのがダメってことなんだもんね。
カーネルおじさんによる美味しくできるニワトリ料理パターン
╰( ´◔ ω ◔ `)╯ 毎回記事本体じゃなくて、ナンセンス釣りタイトルを考えるのに時間を費やしてる気がしなくもない
今朝は Swiff の型について考えたような気がする。
自分の中では Swiff も Uva も文法的なところが違うだけのようになってきたので、どんどこどーん!
Swiff は Swift や Rust、Kotlin をインスペクトしているので、let
は変数宣言で、val
は定数宣言になってる。
すごく簡単に書くとこんな感じ:
("let" | "val") <識別子> [":" <型ヒンティング>] "=" <値> ";"
val
だった場合は、<値>
必須だとか色々あるけど、こんな風に変数または定数を定義する。
例を示すとこんな感じ:
let hoge = 42; let piyo : string = "Cunky bacon!!"; val TeddyBearFee = 6000;
上記の例で val
で宣言された識別子、ええっと、定数が UpperCamelCase で表記されていることに気がついた人もいるかもしれない。
そして、定数が UpperCamelCase でないとコンパイラがブーブー言うだろうと思った人は安心していい。
そんなことはない。
Wikipedia の Swift の記事において var
*1 で宣言された識別子は定数と呼ばれていた。
でも、そうじゃなくて、変更できない変数あるいは束縛と呼ぶべきだったのだ。
典型的な関数型プログラミングの考え方では、私たちが変数と呼ばれているものは実は値に名前が書かれた札が紐で結ばれているだけで、
それは分かちがたく結びついているので変更できない。
このことを不変更性を持つと呼ぼう。
札から下がった紐が果てしなくこんがらがって絶対に解くことはできないのだ。
とはいえ、実用的なプログラミング言語にそのようなパズルみたいな難解な代物を持ち込むべきではないと今でも思っている人たちも大勢いるわけで、 彼らにも配慮してやらなければならない。
私としては不変更性はすごく重要だと思っているので Uva では普通に宣言した変数は不変更性を持つようになっている。
どうしても変更可能な変数を宣言したい場合は variable
アノテーションをつければいい。
Swiff はカジュアルな言語を志向しているので、型ヒンティングは :
(コロン)で識別子の後ろに付けることになる。
もちろん、そんな面倒なことをしなくても、型推論によってある程度変数の型はコンパイル時に決定される。
Uva でも型推論で同じように変数の型は決定されるけど、そうしたい旨をコンパイラに伝えないといけない。
それが auto
キーワードだ。
Uva は Swiff の後置に対して前置タイプなので、型ヒンティングを必ず付ける必要が生じる*2。
でも、Uva には静的型付き言語の顔をしてほしかったため、C++ から auto
を取ってきた。
(。ŏ﹏ŏ) こうしてみると、Uva と Swiff って性格が違うんだね
╰( ´◔ ω ◔ `)╯ そうだな
更に、関数定義でも fun
ではなく、def
を採用した。
def is_nil(x : T?) : bool { match x { is T => true, is Nil => false } }
あと、match
式 (・∀・)イイ!!
という感じだったので、switch
は無し。
return
もあるけど、基本的には最後の値が返されるという感じ。
後置 if
とか 後置 unless
や while
、until
もあるよ。
let x = if x < Screen.width then x else Screen.width; // :? タイプの if 式 let y = if y < Screen.height { y } else { Screen.height }; // if っぽい if 式
if
は式だし、then 節はかっこつけなくてもいいんじゃないかとかとかとか…………。
Uva をはじめようかなー
エントリーポイント
Uva は決まったエントリーポイントを持たない言語です。
例えば、クラスの外においては Java は一切の文あるいは式(クラス・インターフェイス定義、import
文、package
文を除く)を書くことが許されていませんが、
Uva では許されています。
なので、println( "Hello, World!" );
を main()
の外に書いても構いません。
shared
のこと
shared
というのは一見キーワードのように見えますが、実のところアノテーションの 1 つです。
shared
が付いた関数や変数、クラスなどはこのソースコードの外からでも見えるようになります。
つまり、可視性を司るアノテーションです。
ループ
Uva にはループは for-in
と while
、until
の 3 つがあります。
for-in
は以下のような、C# でいう foreach
の形をもつ for
文です。
for ( auto i in 1..5 ) { for ( auto j in 1..j ) { print( "*" ); } println(); }
標準出力への出力
標準出力に出力する方法の 1 つとして、println()
があります。
これは、何らかの値を出力し、最後に改行を出力するという関数です。
ちなみに、最後に改行を出力しない同じような関数として print()
があります。
print()
や println()
はそれぞれ、process.stdout.print()
、process.stdout.println()
のエイリアスです。
process
オブジェクト
process
はビルトインの現在のプロセスを表すオブジェクトです。
variable String? input = process.readLine();
null
許容型
process.readLine()
の戻り値は String?
です(おそらく)。
String?
の後ろの方の ?
は null
が入っているかもしれない String
型という意味です。
String?
を別の表記(複合型表記)で表すと String|Null
です。
Null
型の唯 1 つのオブジェクトが null
です。
if ( exists input ) { String[] tokens = input.split(); int?[] numbers = tokens.map( int.parse ); }
例えば int.parse()
は整数値にパースできない文字列が渡された場合、null
を返します。
このようなメソッドないしは関数の戻り値型は ? 付きです。
is
式
ある型 T
の null
許容型 T?
の値が null
かどうかを確かめる 1 つの方法が is
式を使うことです。
is
式は右オペランドの値が左オペランドの型あるいは左オペランドの型を継承した型である場合、真を返します。
if-exists
ガード句
もう 1 つの方法が if-exists
ガード句を使う方法です。
Hoge? hoge = getHogeOrNull(); if ( exists hoge ) { // このブロックでは hoge は Hoge 型であることが明確になる。 println( "it's Hoge" ); } else { // このブロックでは hoge が null であることが確実。 println( "it's null" ); }
James VM のこと
Uva Advent Calendar 2016、 5 日目。
ʕ•͡ω•ʔ 今日は JS の Promise のことを調べてた。
James VM は Uva 用の VM です。
正確には、Uva 用の VM になる予定です。
Uva コンパイラ uvac
でコンパイルすると、Uva ソースコードは基本的には James VM 用のバイトコードを生成します。
この James VM バイトコードファイルの拡張子はとりあえず、.james にしておきましょう。
James VM にはイメージが必要です。
Uva のパッケージはイメージごとにインストールできます。(多分)
プロジェクト毎にイメージを作成することができますが、通常はイメージの管理が面倒くさいのでイメージは 1 つでいいんじゃね?
とか、イメージマジウザすぎじゃない?とか言われそうだよねとかでいい考えだと思ったんだけどダメかなーって思っている。
(๑´ڡ`๑) おしまい
Linux なデスクトップ環境でおすすめの 10 のアプリ
Uva Advent Calendar 4 日目。
今日は Linux なデスクトップ環境でおすすめのアプリを紹介していきたいと思います。
10 つ全部 Emacs や Vim になったりした 10 things を見たって?
大丈夫。今回は Emacs や Vim 以外のアプリを紹介するから。
Banshee
Banshee はよさげな音楽プレイヤー。
普段、音楽を聴くのに使ってるよ。
Audacious
Audacious は Winamp ライクな音楽プレイヤー。
いつもは Banshee を使っているんだけど、音楽ファイルを 1 つだけ聴きたいといったときや、Banshee の調子がおかしくなった時などに使うよ。
Firefox
Firefox はみんな知ってると思う。
LibreOffice
Excel ファイルは誰だって扱いたくない。そうだよね?
世の中は Excel ファイルで溢れている。
そんな時は LibreOffice Calc を起動しよう。
EoG (Eye of GNOME)
EoG は GNOME の画像ビューアー。
起動?、起動は結構速いよ。うん。
llpp
PDF を読もうとしたけど、文字が表示されていない?
それは困ったね。
llpp のことを考えてみた?
VLC
知ってる人もいるかもしれないけど、VLC は動画プレイヤーだよ。
もちろん、Windows でも使えるんだ。
Krita
Krita はめっちゃいいよ。
まだあんまり使ったこと無いけど。
いいはずだよ。うん。
Wine
Windows のアプリを使いたいって?
Wine のことは知ってる?
OpenTTD
OpenTTD はゲームだよ!
紳士的振る舞いを紳士 Spec でテストする
╰( ´◔ ω ◔ `)╯ Argu を使ったテストをしようと思って、NUnit でやってみたら、FSharp.Core の 4.3.0 が必要みたいなんだ
ʕ•͡ω•ʔ Argu が FSharp.Core 4.3.0 に依存しているのかな?
╰( ´◔ ω ◔ `)╯ テスト用プロジェクトは 4.4.0 でやってるから、4.3.0 に落とせば良いのかな
さあ、Uva を始めよう
Uva Advent Calendar 2 日目。
今日は Rosetta Code の題材を使ってほにゃららら*1。
配列の宣言
100 の要素を持つ bool 型の配列、doors
を用意します。
variable はこの変数が可変だという意味を持つアノテーションです。
variable を付けない場合、変数は値の再設定が認められません。
variable bool[] doors = new bool[]( 100 );
値の再設定が認められないということが、変数が指している参照のことなのか、実体のことなのかはまだ決まっていません。
for 文
Uva は C 言語風の for 文を使うことができません。
代わりに for-in 文を使うことができます。
for ( int i in 0..doors.length ) { doors[i] = false; }
bool
型のデフォルト値は false
なので、上記の false
に初期化する処理は不要です。
for ( int i in 0..doors.length ) { for ( int j in 0..doors.length ) { if ( ( j + 1 ) % ( i + 1 ) == 0 ) { doors[j] = ! doors[i]; } } }
標準出力への出力 その 2
println()
は stdout.println()
のエイリアスです。
println( "Passes Completed!!! Here are the results" ); println();
また、文字列リテラルに変数の値を埋め込むことができます。
for ( int i in 0..doors.length ) { String status = doors[i] ? "Open" : "Closed"; println( "Door #${d + 1} ${status}" ); }
(๑´ڡ`๑) おしまい
*1:コピペだけの手抜き記事ですという意味
Uva Advent Calendar 一日目
Uva Advent Calendar 1 日目。
今日は 1 日目ということで、Uva じゃないことを書こうかと思います。
ある日、dotnet-cli をインストールしようと思ったんですが、/
がパンパンでビルド中にあぼーんしてしまいます。
これはいかん! と思って、そんなに必要じゃないパッケージを消そうと思いました。
結局のところ、~/ でビルドすることで事なきを得たんですが、その前にやったことを書いておこうと思います。
他のパッケージに必要とされていないパッケージの一覧を得る
ArchWiki によると、「孤立した、他のパッケージに必要とされていないパッケージの一覧を得る」には:
% pacman -Qdt
と打てば良いことがわかります。
これは、pacman -Q
と打ったときと同じフォーマット(<パッケージ名> <バージョン>
)なので、
awk
で { print $1; }
を使うことで、パッケージ名だけの一覧にすることができます。
シェルスクリプトにするとこんな感じです:
% pacman -Qdt | awk '{ print $1; }'
それぞれのパッケージ情報を得る
あとは、それぞれのパッケージのインストール容量を知りたいので、それぞれに yaourt -Qi <パッケージ名>
したいですよね。
AWK スクリプトにすると、こんな感じです:
# gen-package-info.awk { print "yaourt -Qi" $1 " > " $1 ".pacinfo" }
gen-package-info.awk
を使って、こんな風に打ってみます:
% yaourt -Qdt | awk -f gen-package-info.awk | sh
標準出力にパッケージ一覧分の yaourt -Qi ${パッケージ名} > ${パッケージ名}.pacinfo
を出力し、
それを sh
に標準入力として渡すことで、sh
に実行してもらいます。
パッケージ名とインストール容量を抜粋する
あとは ${パッケージ名}.pacinfo
を見ていけば良いのですが、多すぎると、忘れちゃいますよね((ニワトリ頭))。
なんとかして、パッケージ名とインストール容量だけを抜き出せないものでしょうか。
とりあえず、.pacinfo
はこんな感じになっています:
名前 : hiredis
バージョン : 0.13.3-1
説明 : Minimalistic C client library for Redis
アーキテクチャ : x86_64
URL : https://github.com/redis/hiredis/
ライセンス : BSD
グループ : なし
提供 : なし
依存パッケージ : glibc
提案パッケージ : なし
必要パッケージ : なし
任意パッケージ : なし
衝突パッケージ : なし
置換パッケージ : なし
インストール容量 : 109.00 KiB
パッケージ作成者 : Massimiliano Torromeo <massimiliano.torromeo@gmail.com>
ビルド日時 : 2015年10月12日 16時41分02秒
インストール日時 : 2016年11月08日 23時33分42秒
インストール方法 : 他のパッケージの依存関係としてインストール
インストールスクリプト : No
検証方法 : 署名
これもやっぱり、AWK で処理可能です。
$1
が 名前
の時と インストール容量
の時に、$3
が目的の値であることがわかります。
今回は JSON に変換して、Node.JS で処理してみましょう。
JSON に変換する AWK スクリプトがこちらです:
# gen-install-size.awk BEGIN { print "["; } { if ( $1 == "名前" ) { print "{"; print "\"name\": \"" $3 "\","; } if ( $1 == "インストール容量" ) { print "\"install-size\": \"" $3 $4 "\""; print "},"; } } END { print "]"; }
これを使って下のように打ってみます:
% awk -f ./gen-install-size.awk *.pacinfo > ./install-size.json
これによってできた install-size.json
を以下の ranking-install-size.ls
で処理すると多分できます。
# ranking-install-size.ls require! 'package-size.json': package-size-json compare-install-size = (left, right) -> left.install_size - right.install_size package-sizes = package-size-json.map (record) -> name = record['name'] install-size-text = record['install-size'] install-size = parse-float install-size-text if /MiB$/.test install-size-text install-size = install-size * 1000 { name: name, install_size: install-size } for record in package-sizes.sort( compare-install-size ) console.log "#{record.name}: #{record.install_size} KiB"
おしまい。