Petite Chez Schemeをインストール

Chez Scheme Version 8.4

tar -xzvf pcsv8.4-ti3osx.tar.gz
cd csv8.4/costom
./configure --installprefix=~/local --installman=~/local/share/man
make
make install

すると petite と scheme-script がインストールされる。root権限にchownしようとしたりしていろいろエラーが出るがとりあえず無視する。すると、

$ petite
cannot find compatible petite.boot in search path
  "/Users/kaki/lib/csv%v/%m:/usr/lib/csv%v/%m:/usr/local/lib/csv%v/%m"

と言われる。bootパスが間違っているので

petite -b ~/local/lib/csv8.4/ta6osx/petite.boot

で起動できる。そこで

cd ~/local/bin
mv petite petite8.4

petite

#!/bin/sh
exec petite8.4 -b ~/local/lib/csv8.4/ti3osx/petite.boot "$@"

petite-script

#!/bin/sh
exec petite8.4 -b ~/local/lib/csv8.4/ti3osx/scheme-script.boot --script "$@"

としてみた。scheme-script いらなさそうだけどとりあえず保留。

><>(Fish)に入門した

あらすじ

><>という難解プログラミング言語某ゴルフ場に入ったので、入門した。言語の名前上、ググラビリティが非常に低く日本語の情報が見当たらなかったので、ここに日本語で自分の><>入門への道中を記す。あくまで初心者が調べながら書いた文章なので、間違いが多分に含まれている可能性がある。間違いを見付けたら教えてほしい。


(この文章は、Befunger視点で書かれている。前提知識として、(某ゴルフ場の多少カスタマイズされた)Befungeの理解を要求するかもしれない。)

続きを読む

任意の型の引数を無限に消費する空腹関数はHaskell(GHC)では書けないのか?

Schemeでいうと

(define (hungry x) hungry)

みたいなやつ。

ここまではできた。参考: https://github.com/jstolarek/sandbox/blob/master/haskell/Hungry.hs

Prelude> :set -XRankNTypes
Prelude> data Hungry = Hungry { (%) :: forall b. b -> Hungry }
Prelude> let fix f = f $ fix f
Prelude> let hungry = fix id :: Hungry
Prelude> :t hungry % 42 % 'c' % []
hungry % 42 % 'c' % [] :: Hungry

unHungry (上では (%)) 無しでは書けないのかなあ。


(追記 18:38)
できた、のか?
参考:可変長引数をHaskellで。 - ここにタイトルを入力|

Prelude> class Hungry f where hungry :: a -> f
Prelude> instance Hungry a => Hungry (f -> a) where hungry _ = hungry
Prelude> :t hungry 42 'c' []
hungry 42 'c' [] :: Hungry t => t

型クラスにするとそれっぽいものが何故かできた。何故だ?

はじめてのQuineリレー

概要

昨日、自分自身を出力するHaskellプログラムを生成するOCamlプログラムを生成するSchemeプログラムを生成するRubyプログラムを生成するJavaScriptプログラムを生成するCプログラムを書いた。

#include<stdio.h>
int main(){char*g="var p=print;p('puts %%^(format #t!Printf.printf~s~s!(x->string`main=putStr%%S)^.tr *?!...?#;p <<_;$><<?)');p('#include<stdio.h>');print(%cint main(){char*g=%c%s%c;printf(g,47,34,g,34,47);}%c.source);p('_')";printf(g,47,34,g,34,47);}

以下のように動作する。Makefileは後述。

$ make diff
clang -std=c99 -Wall -W -Werror -pedantic -o quine-relay-c start.c && ./quine-relay-c > quine-relay.js
v8 --use_strict quine-relay.js > quine-relay.rb
ruby quine-relay.rb > quine-relay.scm
gosh quine-relay.scm > quine-relay.ml
ocaml quine-relay.ml > quine-relay.hs
runghc quine-relay.hs > goal.c
diff -u start.c goal.c
$ wc start.c quine-relay.*
       2       9     270 start.c
       0       8     287 quine-relay.hs
       0      13     402 quine-relay.js
       0       8     304 quine-relay.ml
       4      15     360 quine-relay.rb
       2      11     333 quine-relay.scm
       8      64    1956 total

動機

SchemeRubyが得意でHaskellOCamlも書けます!」と堂々と言えるようになりたい。ならばそれらの言語でQuineリレーをしよう。思い付いてしまったからには、書かねばなるまい。そう思っていた時期もあった。

かのように決心して書き始めたのだが、存外に難しくはなく、その日のうちにできてしまった。

構想

コンセプト。Quineリレー自体は偉大なる先人が凄いのを成し遂げていらっしゃるし、自分はQuineリレーには初挑戦なので、今回は得意言語のアッピルに重点を置いて、とりあえず高級言語数個での完成を目指すことにした。次に順序が問題となる。Brainf**kやBefungeを入れるでもないのに順序が任意では趣に欠けるというもの。これはなんとなくCを起点にして触った順にした。結果、自分のプログラミングの学びの歴史を辿り最後は初心に帰るという個人的に気持ち悪い大層趣のあるプログラムができあがった。あと、今回の主旨に鑑みて、特定の言語で何重にもエスケープして残りの言語は文字列を出力するだけ、みたいなヒキョウなことはなるべくしないようにした。

もう一つ、追加の制約としてCコンパイラのオプションに -std=c99 -Wall -W -Werror -pedantic を付けることにした。これでこのプログラムがコンパイラも黙る程の真っ当なプログラムであることは確定的に明らか。奇妙な挙動や拡張に依存していたら、コンパイラによってバラバラに引き裂かれることになる。

ついでにちょっと縮めた。

感想

  • 難しいというより面倒臭い
  • 改行のために\nを書くとバックスラッシュで面倒が増えるのでJSのprintを活用
  • JSなら正規表現リテラルが使える→正規表現リテラル内では括弧の対応やらメタ文字が合法じゃないとだめ→エスケープのためにバックスラッシュを入れると面倒が増える→いくえ不明
  • バックスラッシュは排除
  • 多様なリテラルがある言語はこういう時強い
  • raw文字列リテラルがある言語は意外と少ないけど、あるといいなあ
  • 複数行の文字列リテラルが書けない言語は(省略されました)
  • みんな printf のことが好きなんだなあ( ꒪⌓꒪)

付録

Makefile

.PHONY: all clean diff
CC = clang
CFLAGS = -std=c99 -Wall -W -Werror -pedantic
JavaScript = v8 --use_strict
Ruby = ruby
Scheme = gosh
OCaml = ocaml
Haskell = runghc

DIFF = diff -u

START = start.c
GOAL = goal.c
Q = quine-relay
C_EXE = $(Q)-c

all: $(GOAL)

diff: all
	$(DIFF) $(START) $(GOAL)

$(Q).js: $(START)
	$(CC) $(CFLAGS) -o $(C_EXE) $< && ./$(C_EXE) > $@

$(Q).rb: $(Q).js
	$(JavaScript) $< > $@

$(Q).scm: $(Q).rb
	$(Ruby) $< > $@

$(Q).ml: $(Q).scm
	$(Scheme) $< > $@

$(Q).hs: $(Q).ml
	$(OCaml) $< > $@

$(GOAL): $(Q).hs
	$(Haskell) $< > $@

clean:
	rm -f $(GOAL) $(C_EXE) $(Q).js $(Q).rb $(Q).scm $(Q).ml $(Q).hs

あと各処理系のバージョン。Gaucheは開発版の何か。

$ clang -v
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
$ echo -n | v8
V8 version 3.25.30 [sample shell]
>
$ ruby -v
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin13]
$ gosh -V
Gauche scheme shell, version 0.9.5_pre1 [utf-8,pthreads], x86_64-apple-darwin13.4.0
$ ocaml -version
The OCaml toplevel, version 4.02.0
$ ghc -V
The Glorious Glasgow Haskell Compilation System, version 7.8.3

enum型からその中の型へのキャスト

enum型からその中の型へのキャストする underlying_cast を書いた。

#include <cinttypes>
#include <type_traits>
#include <array>
#include <cstdio>

template <class E>
constexpr typename std::underlying_type<E>::type
underlying_cast(E e) noexcept {
  return static_cast<typename std::underlying_type<E>::type>(e);
}

enum class Ki : std::uint8_t {
  momo = 3,
  kuri = 3,
  kaki = 8
};

template <class T>
void p(T n) {
  std::puts("something");
}

template <>
void p(std::uint8_t n) {
  std::printf("uint8_t %" PRIu8 "\n", n);
}

int main() {
  p(underlying_cast(Ki::kaki));
  std::array<int, underlying_cast(Ki::kaki)> a{};
  return 0;
}
$ clang++ -std=c++11 -o underlying_cast underlying_cast.cpp 
$ ./underlying_cast 
uint8_t 8

やったぜ。

Cプリプロセッサマクロ挙動クイズ

#define STR(a) #a
#define STR_(a) STR(a)
#define CONCAT(a,b) a##b
#define CONCAT_(a,b) CONCAT(a,b)
#define M1(a) STR(CONCAT(a, __LINE__))
#define M2(a) STR_(CONCAT(a, __LINE__))
#define M3(a) STR(CONCAT_(a, __LINE__))
#define M4(a) STR_(CONCAT_(a, __LINE__))

int main() {
  puts(M1(a));
  puts(M2(b));
  puts(M3(c));
  puts(M4(d));
}

以上のような foo.c があるとして、

$ clang -E foo.c | sed '/^#/d'

するとどうなるか。つまり、プリプロセッサを通すとどうなるか。

続きを読む

method-missingを作ってみた

勢い余って「適用できるメソッドがなければ method-missing を呼び出す」機能を作ってみた.

(define-generic method-missing)

(define-class <method-missing-generic> (<generic>)
  ())

(define-method apply-methods ((gf <method-missing-generic>) methods args)
  (if (null? methods)
      (apply method-missing gf args)
      (next-method)))

ドキュメントがなくて推測だけど,apply-methods は(sort-applicable-methods で)ソートされた適用可能なメソッドのリストを受け取り,next-method が次のメソッドを呼び出すように設定して,メソッドを呼び出すのだろう.とにかく適用可能なメソッドがなくても apply-methods は(空リストを伴って)呼ばれるようだ.

(define-generic foo :class <method-missing-generic>)

(define-method foo ((num <number>))
  `(number ,num))

(define-method method-missing ((gf <method-missing-generic>) (str <string>) :rest args)
  `(missing ,(~ gf 'name) string ,str))

(foo 42)     ; => (number 42)
(foo "bar")  ; => (missing foo string "bar")


(define-method foo ((num <string>))
  `(string ,num))

(foo "bar")  ; => (string "bar")

呼び出すジェネリックファンクション foo は予め定義しておかないといけないので有り難みは薄い気がする.