Hatena::Groupcoders

ラシウラ出張所 このページをアンテナに追加 RSSフィード

2007/05/19

[] 左結合な中置演算子の作り方  左結合な中置演算子の作り方 - ラシウラ出張所 を含むブックマーク はてなブックマーク -  左結合な中置演算子の作り方 - ラシウラ出張所  左結合な中置演算子の作り方 - ラシウラ出張所 のブックマークコメント

より、無駄を減らして

class infix:
    def __init__(self, func):
        self.func = func
        pass
    def __call__(self, left, right):
        return self.func(left, right)
    def __ror__(self, left):
        return boundleft(lambda right: self.func(left, right))
    pass

class boundleft:
    def __init__(self, func):
        self.func = func
        pass
    def __call__(self, right):
        return self.func(right)
    def __or__(self, right):
        return self.func(right)
    pass

Python-2.5では使い方は以下のようになる。infixが使えるのは二引数で呼び出しできるものでなくてはいけない:

@infix
def mul(a, b):
    return a * b

@infix
def add(a, b):
    return a + b

print 2 |add| 3 |mul| 4 #=> (2 + 3) * 4 = 20

結果から左結合の二項演算子になっていることを確認できる。

旧来の使い方も可能

isa = infix(lambda a, b: a.__class__ == b.__class__)

print [1,2,3] |isa| [] #=> True

右結合は?

Pythonの右結合演算子は、代入関係と**だけになる。まず、代入演算はa += b += cのような連続はパーズエラーになるため、使えない。

唯一**が__pow__や__rpow__で上書きできる。ただし、それを有効にするためにはinstance型は、__coerce__で引数側の型を変換しなくてはいけない。

class infixr:
    def __init__(self, func):
        self.func = func
        pass
    def __call__(self, left, right):
        return self.func(left, right)
    def __pow__(self, right):
        return boundright(lambda left: self.func(left, right.obj))
    def __coerce__(self, other):
        return (self, wrap(other))
    pass

class wrap:
    def __init__(self, obj):
        self.obj = obj

class boundright:
    def __init__(self, func):
        self.func = func
        pass
    def __call__(self, left):
        return self.func(left)
    def __rpow__(self, left):
        return self.func(left.obj)
    def __coerce__(self, other):
        return (self, wrap(other))
    pass

使い方例

@infixr
def comp(f, g):
    return lambda a: f(g(a))

add2 = lambda a : a + 2
mul3 = lambda a : a * 3
add4 = lambda a : a + 4

print (add4 **comp**  mul3 **comp** add2)(1) #=> (1 +2) *3) +4 = 13

実際のところ、右結合演算子が必要な状況はほとんどない。代入、pow演算子、(Rubyのように括弧のいらない)関数適用くらいだが、それは組み込まれている。関数型言語だと、例でも使った関数合成は右結合になる。 foo.bar.buzz はfoo.(bar.buzz)である。関数適用ではfoo (bar (buzz x)))であってほしいからだ。これはpythonにもほしくなるかもしれない。

あと(遅延型)関数型言語リストの結合も右結合になる。これはリスト[a,b,c,...]が意味的に(a,(b,(c,(...,()...))))のように、(","を中置演算子としてみれば)右結合になっているからだろうか。っと思ったが、このリストPythonでいうところのgenerator/iteratorであるため、右結合が自然なのだろう。右結合のappend(alist, append(blist, append(clist, dlist))))は、自然に頭のリストをたどってそれが尽きたら次のappendに入れる。一方、左結合のappend(append(append(append(alist, blist), clist), dlist)は先頭の要素を取り出すにも一番奥のappendにいかなくてはいかなくなる。

pythonリストは左結合の+を使って連結するが、右左どちらでもかまわない。

2007/05/11

[][] 関数の不動点  関数の不動点 - ラシウラ出張所 を含むブックマーク はてなブックマーク -  関数の不動点 - ラシウラ出張所  関数の不動点 - ラシウラ出張所 のブックマークコメント

OCaml:

type ('a, 'b) wrappedFun = Wrap of (('a, 'b) wrappedFun -> ('a -> 'b))

let fixpoint = fun funDef ->
  let unwrap = function Wrap(func) -> func in
  let genFunc = fun wrapped -> funDef (fun n -> (unwrap wrapped) wrapped n) in
  let wrapped = Wrap(genFunc) in
  genFunc wrapped

(* example *)
let factorial = fixpoint (fun fact n -> if n = 0 then 1 else n * fact (n - 1))

open Printf;;
printf "%d\n" (factorial 5)

Haskell:

fix f = f (fix f)

fact = fix $ \fn n -> if n < 1 then 1 else n * fn (n - 1)

main = do
    putStrLn $ show (fact 5)
    return ()

上のMLのようにhaskellで書くとghcでコンパイルがとまらなくなりました。

data Wrap a = Wrap ((Wrap a) -> a)

-- cannot compile, compiler infinit loop
fix f = genfunc wrapped
    where
      unwrap (Wrap g) = g
      genfunc wrapped = f ((unwrap wrapped) wrapped)
      wrapped = Wrap genfunc

fact = fix (\fact -> (\n -> if n == 0 then 1 else n * (fact (n - 1))))
main = putStrLn $ show (fact 10)

[] UTF8でLaTeX(pLaTeX)を使う方法  UTF8でLaTeX(pLaTeX)を使う方法 - ラシウラ出張所 を含むブックマーク はてなブックマーク -  UTF8でLaTeX(pLaTeX)を使う方法 - ラシウラ出張所  UTF8でLaTeX(pLaTeX)を使う方法 - ラシウラ出張所 のブックマークコメント

(追記: platexをやめてxelatexを使おう - ラシウラplatexではなくxelatexを使うやり方を書きました)

いまさらSJISとかEUC-JPとかISO-2022-JPとか使う時代じゃないってことで。

\documentclass[a4j]{jarticle}
\usepackage{url}

\title{UTF8で \LaTeX を使う方法}
\author{bellbind}


\begin{document}
\sffamily
\maketitle

\begin{abstract}
UTF-8でp\LaTeX を処理する方法。
\end{abstract}

\section{環境}

最近の p\LaTeX が入っているならたぶん大丈夫。

debianの場合は、debパッケージのptexがUTF-8に対応していません。
ptetex3
\footnote{\url{http://www.nn.iij4u.or.jp/~tutimura/tex/ptetex.html}}
をローカルにでも入れて使いましょう。
ptetexにも付いてきますが、dvipdfmxはdebパッケージのものでもUTF8に対応できています。

例:
\begin{itemize}
\item TeXインストーラー
\footnote{\url{http://www.ms.u-tokyo.ac.jp/~abenori/mycreate/index.html}}
からWindows上にインストール
\end{itemize}

\section{\TeX ソース}

ふつうの p\LaTeX のソースと同様に記述する。
ただし、ファイルのエンコーディングはutf8にする。
\begin{itemize}
\item xyzzy \footnote{\url{http://www.jsdlab.co.jp/~kamei/}} なら "utf8n"
\end{itemize}

\section{コマンドライン}

コンパイル時に {\tt --kanji=utf8} オプションをつけるだけ。

Windowsの場合:
\begin{verbatim}
$ platex --kanji=utf8 test.tex
$ dvipdfm test.pdf
\end{verbatim}

debianの場合:
\begin{verbatim}
$ platex --kanji=utf8 test.tex
$ dvipdfmx test.pdf
\end{verbatim}


\end{document}

↑をtest.texという名前のファイルにUTF8Nで保存して上記コマンドでビルドできます。

オプション--kanji=utf8はaliasしてもいいくらい

alias platex='platex --kanji=utf8'

ptetex3のdebianへのインストール

サイトの説明どおりに行けば普通にビルド&インストールできます。

自分の場合、~/util/ptetexに入れてます。


問題になるのはmy_optionと必要なパッケージでしょうか。

ビルドに必要なdebパッケージ

このあたりがあらかじめ入れてあればビルド可能です。

まず、指定してある3つのアーカイブをひとつのディレクトリ内にダウンロードします。ptetexアーカイブだけ展開し、ディレクトリを移動します。

my_optionはmy_option.sampleからコピーし作り、一部コメントアウトをはずしていく

  • KANJI_CODE=UTF8
  • XDVI=echo
  • PXDVI=echo
  • PREFIX=/home/bellbind/util/ptetex

$PREFIX/bin/platexになります。

makeはotf、babel含めすべて行うといいです。

で最後はmake install。~/util/ptetex/binにPATHを通して、alias platex='platexr--kanji=utf8'して終わり