vieweditattachhistoryswikistopchangessearchhelp

Haskell

論理学者 Haskell Brooks Curry の名を冠した純粋関数型言語。引数の遅延評価機構が特色。--sumim

情報

処理系

チュートリアル

ユーモア

--sumim





Haskell(Hugs 98) とほぼ同じ役割りのコードを Smalltalk(Squeak) で。
[1..10]  ‥→ (1 to: 10) asArray
filter isLower "aAbBcC"  ‥→ 'aAbBcC' select: [ :each | each isLowercase ]   " ==> 'abc' "
foldr (+) 0 [1..10]  ‥→ (1 to: 10) inject: 0 into: [ :sum :each | sum + each ]   " ==> 55 "
read "3" + 4  ‥→ '3' + 4 あるいは、(Number readFromString: '3') + 4   " ==> 7 "
(read "3")::Int  ‥→ Integer readFromString: '3'   " ==> 3 "
(read "3")::Float  ‥→ Float readFromString: '3'   " ==> 3.0 "
(\x -> x * x) 3  ‥→ [ :x | x * x ] value: 3   " ==> 9 "



fact 1 = 1
fact n = n * fact (n-1)

   :
   ↓

Integer >> fact
	^ self = 1 ifTrue: [1] ifFalse: [self * (self - 1) fact]



qsort [] = []
qsort (h:t) = qsort (filter (< h) t) ++ [h] ++ qsort (filter (>= h) t)

あるいは、

qsort [] = []
qsort (h:t) = qsort [ x | x <- t, x < h ] ++ [h] ++ qsort [ x | x <- t, x >= h ]

   :
   ↓

ArrayedCollection >> qsort
	| h t |
	self size < 2 ifTrue: [^ self].
	h := self first.
	t := self allButFirst.
	^ (t select: [ :x | x < h ]) qsort, {h}, (t select: [ :x | x >= h ]) qsort


[ f x | x <- [a], check x ] は、Smalltalk のブロックに見た目も似ていて近い意味に使えていそうですが、
実はそうではなく、むしろ #select:thenCollect: して新しいリストを生み出すためのたんなる構文。
よって、ファーストクラス・オブジェクトというわけでもなさそうです。
追記:でも、その正体は関数なのでやはりファーストクラスでしょうか。--sumim
[ toUpper x | x <- "aXbYcZ", isLower x ]

   :
   ↓

'aXbYcZ' select: [ :x | x isLowercase ] thenCollect: [ :x | x asUppercase ]   " ==> 'ABC' "
上にも追記しましたが、手続き(あるいは、無名関数)オブジェクトとしての
Smalltalk のブロックに対応するのは、(\x -> x * x) のようです。--sumim


toHexString n 
   | n < 16 = [toHexDigit n]
   | otherwise = toHexString (div n 16) ++ [toHexDigit (mod n 16)]
   where toHexDigit x = "0123456789ABCDEF" !! x

   :
   ↓

Integer >> asHexDigit
	^ '0123456789ABCDEF' at: self + 1

Integer >> asHexString
	self < 16 ifTrue: [^ self asHexDigit asString].
	^ (self // 16) asHexString, (self \\ 16) asHexDigit asString

あるいは、

Integer >> asHexString
	| toHexDigit |
	toHexDigit := [ :x | '0123456789ABCDEF' at: x + 1 ].
	self < 16 ifTrue: [^ (toHexDigit value: self) asString].
	^ (self // 16) asHexString, (toHexDigit value: self \\ 16) asString

5295 asHexString                   " ==> '14AF' "
('16r', 5295 asHexString) asNumber " ==> 5295 "
--sumim


じつはクイックソートとかはあまり感動しなかったけど、これはちょっとキてるフィボナッチ数列の定義。
fib = 1:1:[ a+b | (a,b) <- zip fib (tail fib) ]
残念ながら、Hugs では zip の要素数の不一致でエラーがでちゃうけど、
これがちゃんと効率よく動き、なんの不都合もなく普通に使えるなら
現状の好きな言語で Smalltalk のみのところに Haskell を加えてもいいかも…と思わせるくらい
可能性を秘めたコード片ではある。--sumim



hugs でも動作すると思いますが。。。--nobsun


ど、どうしたんですか急に Haskell。--spiral


ちょっと抽象データ型を勉強しようかと思いまして。
でも、いろいろとおもしろい機能があってなかなか肝心の主題に到達できていません(^_^;)。--sumim



spiral さんは、Haskell 歴、長かったですよね。基本的な質問してもいいですか?
自然数 Natural という型を定義して、Float や Integer と同じように使いたいのですが、
これって初心者には難しいですか? ってかそもそもそんなことは可能なのでしょうか?
ぜんぜんやさしくない「やさしい Haskell 入門 (バージョン98)」にはそれらしき例があるのですが、
手元の Hugs ではうまく動かず、自分が目指しているものを実現してくれるコードかどうかも判断できないのです。
newtype Natural = MakeNatural Integer

toNatural               :: Integer -> Natural
toNatural x | x < 0     = error "Can't create negative naturals!" 
            | otherwise = MakeNatural x

fromNatural             :: Natural -> Integer
fromNatural (MakeNatural i) = i

instance Num Natural where
    fromInteger         = toNatural
    x + y               = toNatural (fromNatural x + fromNatural y)
    x - y               = let r = fromNatural x - fromNatural y in
                            if r < 0 then error "Unnatural subtraction"
                                     else toNatural r
    x * y               = toNatural (fromNatural x * fromNatural y)

   :
   ↓

Reading file "natural.hs":
Type checking
ERROR "natural.hs":10 - Cannot build superclass instance
*** Instance            : Num Natural
*** Context supplied    : ()
*** Required superclass : Eq Natural
--sumim



すみません。解決しました。ここ に訂正のようなものがあって、
newtype Natural = Natural Integer
   deriving (Show, Eq)

toNatural :: Integer -> Natural
toNatural x 
   | x < 0 = error "Can't create negative naturals!" 
   | otherwise = Natural x

fromNatural :: Natural -> Integer
fromNatural (Natural i) = i

instance Num Natural where
    fromInteger = toNatural
    x + y = toNatural (fromNatural x + fromNatural y)
    x - y = let r = fromNatural x - fromNatural y in
             if r < 0 then error "Unnatural subtraction"
              else toNatural r
    x * y = toNatural (fromNatural x * fromNatural y)
というように最初の newtype のところに deriving (Show, Eq) を追加すればOKだったみたいです。
やりたかったのは、最後の fact で、自然数の関数として定義してやれば、
n がマイナスのとき無限ループに陥ることは考えなくてもいいかなぁ…というものでした。
fact :: Natural -> Natural
fact 0 = 1
fact n = n * fact (n - 1)
こちらも思惑通り、うまくゆきました。--sumim



あとはこれで、
fact :: Natural -> Integer
fact 0 = 1
fact n = n * fact (n - 1)
とかできると万々歳なのですが、残念ながらそうは問屋は卸さないようで…。
fact :: Natural -> Integer
fact n = fromNatural (nfact n)
   where
      nfact 0 = 1
      nfact n = n * nfact (n - 1)
などとして、返値の Integer を保証してやらなあかんようです。
これだとわざわざ型で抽象化した意味がないんだよなぁ…。--sumim



うわー。全然長くないですってば。ところで、処理系何使っていますか? hugs だと、プロンプトに Prelude> と出ていると思いますが、このファイル(Prelude.hs)に色々と定義が書いてあります(もう読んでいたらごめんなさい)。Integer の定義もあったようなそうでなかったような。確か、集合だったようなそうでなかったような。思い出せませんが。「やさしい Haskell 入門」、ぜんぜんやさしくないですよねぇ。Tree の型構築子という概念で core dumped した覚えが。--spiral


触発されて、ひさしぶりに hugs 入れてみました。ついでに、graphics ライブラリも。当時は haskell-gtk っつーのがあったのですが、いつのまにかまるちプラットホームな graphics ライブラリが出来ていたのですねぇ。これで、ますますモナドがぁ...(泣)。--spiral


ありがとうございます。
Prelude はひととおり目を通していましたが、なかなか欲しい情報が得られなかったのと言うのが正直なところです。
でも、小さいながらもこうしたフレームワークの実装を、
ユーザーが直接見たりいじったりできるようになっているのは好感が持てますね。--sumim



そうですね。でも、hugs で Boolean を Prelude のまんま定義しようとしたらエラーが出たような記憶があります。ここらへんのしくみはよくわからんです(なんか、適当に作るのがてっとり早いんでしょうかねぇ。.lhs で cgi とか)。--spiral


hugs の対話環境はでは、式の評価はできますが、定義はできないです。定義を書いた
foo.hs ファイルを作成して、hugs の対話環境で :load foo.hs とやると、定義が
読み込まれます。読み込み時に構文解析、依存性解析、型検査、Gコードへのコンパイル
が行われます。エラーがあったときには、:edit foo.hs とやると、$EDITOR が起動する
とおもいます。--nobsun


nobsun さん、ありがとうございます。
試行錯誤でいじっていると、そこいらへんが確かに分かりづらかったりしますね。
あと、module 定義も、直接 :load してしまうと隠蔽が生きてこないので、
別の .hs に改めて import 宣言しないといけないとか…、コンストラクタ関数と型の
区別が付かないとか、わけが分からないうちにいろいろとハマっています(^_^;)。--sumim



このページを編集 (10473 bytes)


Congratulations! 以下の 5 ページから参照されています。

This page has been visited 9485 times.