関数型プログラミング言語Haskell Part3at TECH
関数型プログラミング言語Haskell Part3 - 暇つぶし2ch2:デフォルトの名無しさん
04/02/10 22:17
過去ログ
関数型プログラミング言語Haskell
Part1 URLリンク(pc.2ch.net)
Part2 スレリンク(tech板)

関数型言語
Part1 URLリンク(pc.2ch.net)
Part2 URLリンク(pc3.2ch.net)
Part3 スレリンク(tech板)l50

純粋関数型言語Concurent Clean
スレリンク(tech板)l50

ML!!!!!!
URLリンク(pc.2ch.net)
関数型プログラミング言語ML
Part1 URLリンク(pc2.2ch.net)
Part2 スレリンク(tech板)l50

3:デフォルトの名無しさん
04/02/10 22:17
CommonLisp Scheme MacLisp ....
Part1: URLリンク(piza2.2ch.net)
Part2: URLリンク(pc.2ch.net)
Part3: URLリンク(pc.2ch.net)
Part4: URLリンク(pc.2ch.net)
Part5: URLリンク(pc3.2ch.net)
Part6: URLリンク(pc3.2ch.net)
Part7: URLリンク(ruku.qp.tc)
Part8: URLリンク(pc2.2ch.net)
Part9: スレリンク(tech板)
Part10: スレリンク(tech板)l50

CommonLisp初心者スレ
スレリンク(tech板)l50

Emacs Lisp
Part1 スレリンク(tech板)
Part2 スレリンク(tech板)l50

4:デフォルトの名無しさん
04/02/10 22:23
4

5:デフォルトの名無しさん
04/02/10 22:24
5までいってないけど書き込んでもいいのかな?
>>1乙。
# MLスレの571他です。

6:MLスレ662
04/02/10 22:27
>>5
関数スレ見たらもう張るものもないので

7:デフォルトの名無しさん
04/02/10 23:19
>>1
otu!

8:デフォルトの名無しさん
04/02/11 00:46
Control.Exception にある catch や try や handle って IO a の型がからんでくるから、IO 関係ないとこだと使えないよね。
IO 関係ない関数での引数が気に入らないとかのエラー処理は、Maybe でやるのが Hakell 流なんでしょうか?
それとも容赦なく error が使っちまうべきなんだろうか?


9:デフォルトの名無しさん
04/02/11 00:52
>>8
>  IO 関係ない関数での引数が気に入らないとかのエラー処理は、Maybe でやるのが Hakell 流なんでしょうか?
Yes.  Maybeがモナドであることの有難味がわかるよ。

10:デフォルトの名無しさん
04/02/11 09:26
>>9
Maybe だといちいち Just か Nothing か判定して、
fromJust とかしいといけないから、めんどうだと思ったんだけど。
いまいち自分が Maybe を理解してない気もするな。

> Yes. Maybeがモナドであることの有難味がわかるよ。
その有難味を具体的に教えてください。


11:デフォルトの名無しさん
04/02/11 12:29
>>10
例えば
-- f, g x, h xのいづれかがNothingを返したとき、value_in_error_caseを返す。
(f >>= g >>= h) `maybeCatch` value_in_error_case

ここで
maybeCatch = flip . fromMaybe
# ヒントをもらったら答えを聞く前に自分で考えてみるようにしたほうがいいと思う。

しかし、本当に
>  引数が気に入らない
が問題だというなら、より正しい対処は(適切な抽象型をもちいるなどして)
そんなことがおこらないようにすること。
何か計算の結果が不確定である場合はしかたがないが。

アボートしていいプログラムやassertionならそもそもIOでのcatchもtryもいらない。
errorでいいし、時にはパターンマッチの失敗だけでいい。
f x | validity_check x = ...

12:デフォルトの名無しさん
04/02/11 18:55
>>10
> その有難味を具体的に教えてください。
いちいち Just か Nothing か判定したり、
fromJust とかしなくていいところ。

13:デフォルトの名無しさん
04/02/11 20:52
そっか、すぐ Maybe 外すことばかり考えていたけど、
(Just x) >>= k = k x
Nothing >>= _ = Nothing
とかで、気にせず Maybe 付いたままでいけばいいんだね。
どうもありがとう。


14:デフォルトの名無しさん
04/02/13 07:34
>>11
小さなことだけど。
× flip . fromMaybe ○ flip fromMaybe
ですよね。

15:デフォルトの名無しさん
04/02/15 18:09
OO 言語だと、最初は大体 bank accounts の説明から始まりますよね。
Haskell で bank accounts を実装するとどうなるのでしょうか。

16:デフォルトの名無しさん
04/02/15 19:03
>>15
bank accountsと一口にいわれてもよくわからないが…
こういうこと(カプセル化)でないなら、
期待しているものが載ってるURLをくれ。

ポリモルフィズムはtype class。
継承は難しい。
# OOA, OODが全てではない。

-- テストしてない
module BankAccount (
    -- Do not export any constructor.
    name, money, newAccount
    --, query, ...etc
    ) where

data Account = Account String Integer
name (Account s m) = s
money (Account s m) = m
newAccount (s, m) = Account s m

-- data Database = Database [Account]
-- query (Database as) nm = filter ((== nm).name) as

17:デフォルトの名無しさん
04/02/15 19:16
>>15
> OO 言語だと、最初は大体 bank accounts の説明から始まりますよね。
考えが古典的過ぎるのでは?

C の構造体がどうのこうのとか。


18:デフォルトの名無しさん
04/02/15 20:04
>>16
こういうのをお願いします。アカウントを複数作れて、それぞれに withdraw, deposit
可能な感じです。

URLリンク(mitpress.mit.edu)

>>17
状態遷移を扱う例が他に思いつかなかったもので。OO かどうかにはこだわっていません。

19:デフォルトの名無しさん
04/02/15 21:33
>>18
depositだけ実装。

どうしても
> (withdraw 25)
> 75
> (withdraw 25)
> 50
こんなことがしたい、という意味?

それとも、こういう機能があればいいのか?
例:
$ ./a.out
Print
>> Status: [(0,100),(1,1000),(2,300)]
Deposit 1 300
Deposit 2 400
Print
>> Status: [(0,100),(1,1300),(2,700)]
^D

前者なら、
make_withdraw :: IORef Account -> Money -> IO Money
make_withdraw ref money = 
    do {x <- readIORef ref; writeIORef ref (x - money); readIORef ref}

というのを作っておいて、
ref_account <- newIORef newAccount
let withdraw = make_withdraw ref_account -- :: Money -> IO Money
とする。

後者なら、普通は前者のような設計はしない。

20:19
04/02/15 21:34
>>19
一行目は編集ミスなので無視してくれ。

21:デフォルトの名無しさん
04/02/15 21:44
>>19
× make_withdraw :: IORef Account -> Money -> IO Money
○ make_withdraw :: IORef Money -> Money -> IO Money

22:デフォルトの名無しさん
04/02/15 22:27
>>19
どうもありがとうございます。
毎回出力する必要は無いので、後者だと思います。

23:デフォルトの名無しさん
04/02/15 22:46
>>22
>  毎回出力する必要は無いので、後者だと思います。

なんかずれてるような。
> (withdraw 25)
> 75
> (withdraw 25)
> 50
このwithdrawは(同じ引数に対して別の値をかえすので)
関数じゃないというのはわかってる?

だから、
withdraw :: Int -> Int
ではなくて
withdraw :: Int -> IO Int
になる。別にIO Intにしたからって毎回出力するわけじゃないよ。

24:デフォルトの名無しさん
04/02/15 22:53
>>22
depositだけ実装。
============================
module Main where
import Data.FiniteMap
import Data.Maybe
type Database = FiniteMap Int Int
-- errors are silently ignored.
deposit :: Database -> (Int, Int) -> Database
deposit db (nm, mon)
    = fromMaybe db (lookupFM db nm >>= return . addToFM db nm . (+ mon))
testDB :: Database
testDB = listToFM [(0, 100), (1,1000), (2, 300)]

data Cmd = Deposit Int Int | Withdraw Int Int | Print | Error
  deriving Read

============================
続く

25:デフォルトの名無しさん
04/02/15 22:54
============================
main = loop testDB
  where
    loop db = do  s <- getLine
                  cmd <- catch (readIO s) (\e -> return Error)
                  case cmd of 
                    Deposit i m ->  do  loop $ deposit  db (i, m)
                    Print ->  do  putStrLn $ ">> Status: " ++ show (fmToList db)
                                  loop db
                    _ ->  do  putStrLn ">> Sorry, not implemented"
                              loop db
============================
終わり

26:デフォルトの名無しさん
04/02/16 21:05
>>23
どうもありがとうございます。

>このwithdrawは(同じ引数に対して別の値をかえすので)
>関数じゃないというのはわかってる?

なるほど。感覚的に難しいですね。頂いたコードはじっくり読ませて頂きます。
初心者なもので、時間がかかりそうですが。

27:デフォルトの名無しさん
04/02/17 00:04
HaskellにLispの疑似関数型プログラミング感覚を持ち込むとはまる罠

28:デフォルトの名無しさん
04/02/18 09:12
Haskell の短めのサンプルコードがたくさん解説されたり、アーカイブでまとめられている
サイトはありますか?

29:デフォルトの名無しさん
04/02/18 10:04
The Haskell School of Expression

30:デフォルトの名無しさん
04/02/18 22:41
>>28
URLリンク(rwiki.jin.gr.jp)

UNIXコマンドのHaskellでの実装が多数あります。
というか、僕が書いたものが多いですが。
wikiなので勝手に書きこんじゃいました。
解説はしてませんが、短いコードが多いです。
参考になればうれしいです。
それと、メール欄にsageと書いておくことをようやく学びました。

31:デフォルトの名無しさん
04/02/18 23:15
>>28
Preludeの関数を書く、ついてくるPreludeを読むのがお薦め。

32:デフォルトの名無しさん
04/02/18 23:31
>>30のリンクをみて。

uniq 改良版(getArgs...はかわらないのでstdin用)
--
import Data.List
main = interact $ unlines . map head . group . lines
--

basename, wcあたりも面白そうだ。

33:デフォルトの名無しさん
04/02/19 06:01
>>32
やられた。
そうか、groupが使えたか。
ちょっと悔しいな。
改良版も加えておきます。

34:28
04/02/19 11:04
皆さんありがとうございます。
いろいろなコードをちまちまハックしたいと思います。

Haskell はまだリファレンスだけでは全くかけないので。

35:デフォルトの名無しさん
04/02/19 12:48
a = [0, 1, 2, 3, 4] てなリストがあったとき、
f 3 a => [[0, 1, 2], [1, 2, 3], [2, 3, 4]]
といった値を返す関数 f が欲しいのですが、
Haskell に標準であるでしょうか?

36:デフォルトの名無しさん
04/02/19 14:33
List.hsとPrelude.hsを探したけど、無かった。
無いとは言いきれないけどね。
いちおうお求めの関数は
f :: Int -> [a] -> [[a]]
f num lst
| length lst >= num = take num lst : f num (tail lst)
| otherwise = []
でいいとは思います。

37:デフォルトの名無しさん
04/02/19 14:41
あ、インデントが。
f num lst以下の2文はインデントを深くしないと、だめです。
いちおう念のため。

38:デフォルトの名無しさん
04/02/19 14:57
myTakeを定義しておいて、(長さが足りないとNothing)

g :: Int -> [a] -> [[a]]
g num lst = mapMaybe (myTake num) (tails lst)

これだとlst >> numでもOK

39:デフォルトの名無しさん
04/02/19 15:01
myTake :: Int -> [a] -> Maybe [a]
myTake n _ | n < 0 = Nothing
myTake n _ | n == 0 = Just []
myTake n (x:xs) = case myTake (n-1) xs of
Just xxs -> Just (x:xxs)
Nothing -> Nothing
myTake _ [] = Nothing

40:デフォルトの名無しさん
04/02/19 15:37
takeMaybe :: Int -> [a] -> Maybe [a]
takeMaybe n []
| n == 0 = Just []
| otherwise = Nothing
takeMaybe n (x:xs)
| n < 0 = Nothing
| n == 0 = Just []
| otherwise = takeMaybe (n-1) xs >>= \r
-> Just (x:r)



41:デフォルトの名無しさん
04/02/19 16:59
>>30 wc.hs 書いてる人につっこみ。
data は複数形、単数は datum.

-- 知っててやってるんだったら無視して下さい。
-- (data って変数名使えないから、とか。)

あと下から4行目の data は datas の typo でしょう。


42:デフォルトの名無しさん
04/02/19 17:00
こんなのでもいいかも。

import List
h num lst = [ take num x | x <- tails lst, length x >= num ]

i num = map (take num) . filter ((>=num) . length) . tails

43:デフォルトの名無しさん
04/02/19 17:03
だんだんエレガントにしようとするところが関数型言語スレらしいな。
#############################
import Data.Maybe
-- 再帰で書いてみた
f n xs = catMaybes $ f' n xs
    where   
        f' n [] = []
        f' n xxs@(x:xs) = (takeJust n xxs):f' n xs

-- AKA myTake and takeMaybe
takeJust 0 xs = Just []
takeJust n [] = Nothing
takeJust n (x:xs) = takeJust (n - 1) xs >>= \xs -> Just (x:xs)

44:デフォルトの名無しさん
04/02/19 17:12
>>42
>>36(無限リストにつかえない、何度もlengthを求める)よりは
いいけど、takeとlengthを両方使うのは無駄がおおいのでいまいちかと。

-- テストしてない。多分遅い。
h num lst = filter ((== n) . length) $ f' num lst 
  where 
    f' num [] = []
    f' num lst = take num lst:f' num (tail lst)

45:デフォルトの名無しさん
04/02/19 17:15
>>44
訂正
  >>36(無限リストにつかえない、何度もlengthを求める)よりは
と同じだね。

46:デフォルトの名無しさん
04/02/19 17:22
>>41
そうか、そういえばそうだったな。
datasなんて単語はないのか。
指摘してくれてありがとう。
ま、いまのところは和製英語ってことで...。
そのうち直します。
日本人だと変数名には苦労するよね。

タイプミスは直しておきました。

47:デフォルトの名無しさん
04/02/19 17:42
>>44
なるほど。
lengthを軽々しく使わないほうがいいのかもな。
じゃあ、こんなので

j num = map (take num) . filter (biggerOrEqual num) . tails

biggerOrEqual :: Int -> [a] -> Bool
biggerOrEqual 0 _ = True
biggerOrEqual n [] = False
biggerOrEqual n (x:xs) = biggerOrEqual (n-1) xs

48:デフォルトの名無しさん
04/02/19 18:05
>>47
無限リスト対応問題のほうはそれでいけるね。

>  biggerOrEqual :: Int -> [a] -> Bool
こういうのが欲しくなることは結構ある。おれは
大体再帰で頭を落としていくようにくむから、[]との比較ですむけど。
書くならこうかな。

biggerOrEqual n xs = [] /= drop n xs

49:48
04/02/19 18:08
biggerOrEqual  -> longerThan

50:デフォルトの名無しさん
04/02/19 18:14
longerThan だと Equal が含まれないよ。


51:48
04/02/19 18:21
>>50
だからそうかえたんだよ。

52:デフォルトの名無しさん
04/02/19 18:26
>>48
なるほど、dropはnが大きすぎると[]を返すんだね。
きれいなやりかただ。

で、35の関数はわかりやすさと効率を考えると
以下のものがいいということになる?

38とほぼ同じ。少し見やすくしてみた。
効率がいいのはこれなのかな。
それとnum < 0のときはデフォルトのエラーを起こすようにした。

k num = mapMaybe (takeOfMine num) . tails

takeOfMine 0 _ = Just []
takeOfMine n [] = Nothing
takeOfMine n (x:xs) = maybe Nothing (Just . (x:)) $ takeOfMine (n-1) xs

53:デフォルトの名無しさん
04/02/19 18:39
>>52
そんなもんかな。
# 個人的にはtakeOfMineは>>43のtakeJustのほうが
# Haskellらしくて好きだけどね。(48 == 43だったりする:-)

54:デフォルトの名無しさん
04/02/19 19:02
>>53
Maybe Monadってやつね。
僕も好きだな。
でもこっちのほうが好き。

takeJust n (x:xs) = do xs <- takeJust (n-1) xs
return (x:xs)

なんか手続き型言語に擬態してるかんじが好き。

55:デフォルトの名無しさん
04/02/19 19:08
なんだろ、インデントが重要な言語だと、困るよね。
どうしたらいいんだろう。
上の例ではreturn (x:xs)はxs <- takeJust ...にきっちり合わせないとエラー。

56:by Chalice
04/02/19 19:30
>>55
> なんだろ、インデントが重要な言語だと、困るよね。
いや、困らん。
…でも困る人は{...;..;.}って書けばいい。

とここまでかいて、他の人はIEとかで
プロポーショナルフォントでみているのだと気づいた。困るかも。

57:デフォルトの名無しさん
04/02/19 21:47
k 0 がポイント:

k 0 xs = [[]] ++ [[]|x <- xs]
k n xs = [x:y|(x,y) <- zip xs (k (n-1) (tail xs))]

58:デフォルトの名無しさん
04/02/19 22:00
>>56
  インデントを掲示板でちゃんと表示できたらいいと思ったからさ。

> takeJust n (x:xs) = do xs <- takeJust (n-1) xs
> return (x:xs)

こう書けばいいのかな。

59:デフォルトの名無しさん
04/02/19 23:27
>> 57
同じトピック内で同名関数が定義されたため、参照透明性が破られてしまいますた。

は冗談として、
m 1 xs = [[x] | x <- xs]
m n xs = [x:xs | (x,xs) <- zip xs $ m (n-1) $ tail xs]
でどうだろう。

60:デフォルトの名無しさん
04/02/20 06:33
>>57,59
かなりきれいな解法だと思う。
いままでで一番いいかも。

61:デフォルトの名無しさん
04/02/20 13:47
>>59
いや,f 0 にはそれなりの根拠があるので生かしておいて

f n [] = []
f n xxs@(x:xs) = top n xxs ++ f n xs
top 0 xs = [[]]
top n [] = []
top n (x:xs) = map (x:) $ top (n-1) xs

62:デフォルトの名無しさん
04/02/20 13:52
xxs@(x:xs)は不要なパターンでした

f n [] = []
f n xs = top n xs ++ f n (tail xs)
top 0 xs = [[]]
top n [] = []
top n (x:xs) = map (x:) $ top (n-1) xs


63:デフォルトの名無しさん
04/02/20 16:24
>>61
take* n ≒ top だね。map, ++ の使いかたあたりが微妙に遅そうにみえる。
>>57が綺麗でよさそう。
#  k 0 xs = []:[[]|x <- xs]
#  k n xs = zipWith (:) xs (k (n-1) (tail xs))

64:デフォルトの名無しさん
04/02/20 16:29
zipWith ... 忘れていたよ。


65:35
04/02/20 17:03
>>36-64 みなさまありがとうございますm(_ _)m
私じゃぜんぜん思いつかないエレガントな解で、惚れ惚れいたしました。

66:デフォルトの名無しさん
04/02/21 16:44
どういたしまして。もう一つ:

f n xs = zipN $ take n $ tails xs
zipN xss = if any null xss then [] else map head xss : zipN (map tail xss)

ただし f 0 xs で暴走。

67:(define (´∀`) 'マターリ)
04/02/22 10:08
処理系が落ちてこないので、試さずに挑む。
f n xs = [[xs !! (x + y) | y <- [..n-1]] | x <- [..(length xs)-n]]

68:デフォルトの名無しさん
04/02/22 11:23
>>67
たぶん、
× [..n-1] [..(length xs)-n]
○ [0..n-1] [0..(length xs)-n]
でしょう。

この場合、僕がはじめに作った関数同様、
無限配列で使えないので解としては、やや劣ると思われます。
それと、いちいち(!!)を使うのは効率上どうなんだろうか。
処理系なしで作ったのならしかたないか。
普段はlispを使っているようですね。
はじめにいれる処理系はhugsがおすすめ。
多少なじんできたら、がんばってghcをいれるといいかも。

>>66
いいね。
これもわりと感動もんかも。
単純な処理だと思っても以外と奥が深いもんだな。

以下は別に新しい考えかたは何もないですが、
上のほうで作っていた関数を見やすくしてみました。

p n xs = if drop (n-1) xs == [] then [] else take n xs : p n (tail xs)

dropとtakeを両方使ってるあたりが泥臭いかも。
無限配列を扱えるもののなかで最も素直な解だと思う。どうかな。

69:デフォルトの名無しさん
04/02/22 11:38
>>68
しまった。
書き込んでから気付いたのだが、これだと
p :: Eq a => Int -> [a] -> [[a]]
になってしまう。
まあ、素直な解ということで許してほしい。

70:デフォルトの名無しさん
04/02/22 11:53
もうひとつ素直な解を。

# q n = filter ((==n).length) . k n
# where k _ [] = []
# k n xs = take n xs : k n (tail xs)

どうだろう。

71:(define (´∀`) 'マターリ)
04/02/22 12:31
f n xs = take ((length xs)-n+1) [take n x | x <- tails xs]

f n xs = filter ((==n).length) [take n x | x <- tails xs]

72:デフォルトの名無しさん
04/02/22 17:17
>>70
>>44の#と一緒。

73:デフォルトの名無しさん
04/02/22 17:48
>>71
> f n xs = filter ((==n).length) [take n x | x <- tails xs]

でも素直でわかりやすい。同じだけど:

f n xs = filter ((==n).length) $ map (take n) $ tails xs

「関数のn乗」って関数はなかったんでしたっけ:

f n xs = (iterate chop $ map (take n) $ tails xs) !! n
chop (x:xs) = if null xs then [] else x : chop xs

f n xs = map (take n) $ chopn n $ tails xs
chopn n xs = fst $ foldr _chopn ([], n) xs
where _chopn x (xs, n) = if n > 0 then (xs, n - 1) else (x:xs, 0)


74:デフォルトの名無しさん
04/02/22 18:12
>>73
「関数のn乗」 -> ない。
chop -> init 

> f n xs = map (take n) $ chopn n $ tails xs
> ....
無限リストに使えん。

気持ちは分かるんだが、
    新しい良いアイディアが含まれていなかったり、
    明らかに良くない方法だったりするものを
無闇に書き込むのは止めないか?(せめて欠点を併記するとか)

他の初心者が無分別に使うかもしれないし、
いいアイディアのものが埋もれる。
中級者以上(?)には面白くないし。

75:デフォルトの名無しさん
04/02/22 18:59
>>74
> 「関数のn乗」 -> ない。

なぜないんでしょう,あってもよさそうなのに。

> chop -> init

ありがとう。では直しておきます。

f n xs = (iterate init $ map (take n) $ tails xs) !! n

これは無限リストで大丈夫ですね。

> 新しい良いアイディアが含まれていなかったり、
> 明らかに良くない方法だったりするものを
> 無闇に書き込むのは止めないか?(せめて欠点を併記するとか)

欠点を併記するというのはいいですね。でも,今まで前を拾うこ
とばかりしいたから,今度は後ろを落としてみたらどうかという
発想なので「無闇に」というのとは違いますよ。

76:デフォルトの名無しさん
04/02/22 19:20
> 「関数のn乗」
手許に処理系ないんだけど、foldl とか (.) とかで簡単に作れそうな。

77:74
04/02/22 20:18
>>75  
> 発想なので「無闇に」というのとは違いますよ。
失礼。
あなただけに書いたわけではなくて、>>70-71などを指していた。

> 「関数のn乗」
(iterate f x) !! n が普通なんだろうけど、
自分でtail recursiveな
nest :: (a -> b) -> a -> Int -> b
nest' :: (a -> b) -> a -> Int -> b  -- strict
あたりを書いたほうが、速くていいね。
標準にあったほうがいいというのに同意。

> 手許に処理系ないんだけど、foldl とか (.) とかで簡単に作れそうな。
foldlは無駄な処理をするのでまずい。
composition f n = foldr (.) id $ replicate n f
あたりか。

78:74
04/02/22 20:18
最後は>>76宛。

79:74
04/02/22 20:19
なんどもすまん。
  nest :: (a -> a) -> a -> Int -> a
だね。

80:デフォルトの名無しさん
04/02/23 21:34
>>77
> 標準にあったほうがいいというのに同意。
ですよね。標準でないのは f^n は複数の n に対して評価する
可能性があるのでリストにキャッシュしておけ,という主張か
とも思ったのですが。あっても悪くない気がします。


f n xs = (transpose $ map inits $ tails xs) !! n
(制限:n は xs のサイズ以下,無限リスト可)

81:デフォルトの名無しさん
04/02/29 06:43
なんとなくテクニックの紹介をしてみる。

Haskellのリストは一つの型しか保持できない。
しかし、複数の型であっても、その間に「関係」があれば、
それらの型をラップし、一つのリストにいれた上で使用することができる。
--------------
{-# OPTIONS -fglasgow-exts #-}
-- different types
data A = A String deriving Show
methA (A x) = length x
data B = B Int deriving Show
methB (B x) = x
-- but they have the methods of the same return type Int
data C = forall x. C x (x -> Int)
runC (C x f) = f x
testC = map runC [C (A "I am A") methA, C (B 100) methB]
-- if they belong to the same type class
data ShowC = forall x. (Show x) => ShowC x
instance Show ShowC where
    show (ShowC x) = show x
testShowC = show [ShowC $ A "I am A", ShowC $ B 100]
-- nearly nonsense
data X = forall x. X x

82:デフォルトの名無しさん
04/03/03 22:00
sage

83:デフォルトの名無しさん
04/03/23 15:38
GHC-6.2.1 released

84:デフォルトの名無しさん
04/03/23 22:23
Functional Programming With Haskell
URLリンク(www.amazon.com)

久々の新刊かも

85:デフォルトの名無しさん
04/03/23 22:46
>>84
豪快に割引されてますな。


86:デフォルトの名無しさん
04/03/23 22:49
前スレでガイシュツだったのか。
スレリンク(tech板) #554
一年以上も前に。

87:デフォルトの名無しさん
04/03/24 12:00
wxHaskell使ってる人っている?

88:デフォルトの名無しさん
04/03/24 16:27
>>84
ペーパーバックで5000円か…

89:デフォルトの名無しさん
04/03/25 06:54
>>87
できあがる実行ファイルがでかすぎる

90:デフォルトの名無しさん
04/03/30 23:30
>>89
Minimulコードでどれぐらい?

91:デフォルトの名無しさん
04/03/31 02:56
>>90
@ Mac OS X 10.3

--- Hello.hs
module Main where
import Graphics.UI.WX

main :: IO ()
main = start hello

hello :: IO ()
hello =
   do
    f <- frame [text := "Hello world!"]
    quit <- button f [text := "Quit", on command := close f]
    set f [layout := widget quit]
---

$ ghc -package wx -o hello Hello.hs

で、helloのサイズが7M強。

92:デフォルトの名無しさん
04/03/31 17:53
stripして3M弱だな。

93:デフォルトの名無しさん
04/04/03 19:31
そりゃすげえな

94:デフォルトの名無しさん
04/04/03 19:37
よくしんねぇけど、
ツールキット全部そんなかに入ってんじゃないの?
だったら仕方ねぇと思うけど。
外出しには出来ねぇのかな?

95:デフォルトの名無しさん
04/04/07 21:00
GHC を ports の導入されていない FreeBSD に導入したいんだが
どうすればいいのだろう?

96:デフォルトの名無しさん
04/04/07 21:11
make install

97:デフォルトの名無しさん
04/04/07 21:13
a) portsを入れてmake install
b) packageを持ってきてpkg_add


98:デフォルトの名無しさん
04/04/07 21:47
みんなまずインタプリタで開発して、
安定してきてリリースする間際にコンパイラに移行するの?
インタプリタで正常動作してるけど、コンパイラではうまく動かないってこと多い?
Haskellってコンパイル撃遅い(というか長い)ッてきいたけどマジ?

99:デフォルトの名無しさん
04/04/07 22:07
>>96
GHC のコンパイルには GHC バイナリが必要です

>>97
ports や package は教育上入れてもらえない学生さんなんですよ

100:デフォルトの名無しさん
04/04/08 14:25
>>99
FreeBSD の ftp サーバの ports/distfiles に
ghc-<version>-i386-unknown-freebsd-boot.tar.bz2 があるからこれを展開して,
ghc のコンパイル時にこの展開先にある ghc を指定してコンパイルすればok.

ちなみに ports も同じことをしている(処理が自動化されてるだけ).

>>98
コンパイルはたしかに激遅.
プログラマが楽するためにコンピュータに頑張ってもらってる感があるね.

101:デフォルトの名無しさん
04/04/08 15:40
マニュアル印刷したいんだけど、1枚のHTMLにしてくんないかな。印刷しづらい。
URLリンク(www.sampou.org)


102:デフォルトの名無しさん
04/04/08 15:53
>>101
そんなのちょこっとスクリプト走らせれば楽勝だろ?

103:デフォルトの名無しさん
04/04/08 19:12
>>98
> みんなまずインタプリタで開発して、
おれはそうしてる。GHCiでときどきHugsでチェック。

> インタプリタで正常動作してるけど、コンパイラではうまく動かないってこと多い?
そんな経験は無い。

104:デフォルトの名無しさん
04/04/08 20:10
>>100
ありがとう

試してみてうまくいったらまた報告します

105:デフォルトの名無しさん
04/04/08 22:55
NHCの方が良質のコードを生成するって聞いたことあるけど、
もう今は昔の話なのかな?

106:デフォルトの名無しさん
04/04/08 23:14
このスレでも聞いてみる。
Scheme,OCaml,Haskell,Clean、覚えて「損しない」「一番得」
な言語はどれ。ぶっちゃけ周辺ライブラリーが充実してるのどれ。

107:デフォルトの名無しさん
04/04/08 23:20
>>106
得するのは、全部覚えること。
得しないのは、ひとつしか覚えないこと。

108:デフォルトの名無しさん
04/04/08 23:54
>>106
若いなら全部やれ

109:デフォルトの名無しさん
04/04/09 00:27
>>105
コンパイルは速いけどね。
Hugs/GHC共通のHierachical moduleの多くが使えないのが痛すぎる。

今試しに
main = interact id
をnhc98(FreeBSD-CURRENT, from ports)でコンパイルしたらbus error....

110:デフォルトの名無しさん
04/04/09 00:34
r抜けてたHierarchical

111:デフォルトの名無しさん
04/04/12 16:54
>>106
統計やるならRが結構ナイスだ。

112:デフォルトの名無しさん
04/04/12 22:37
>>110-111
Rスレはこっちに↓あ~る

= 統計解析フリーソフト R =
スレリンク(math板)

113:デフォルトの名無しさん
04/04/14 12:02
工科大の
URLリンク(www.teu.ac.jp)
の問題1 ですが、

> sigma :: (Int -> Int) -> (Int -> Int)
> 上記の関数sigmaを,1) ラムダ記法を使って,2) 関数の部分適用を使って,定義せよ.ただし,sigma fは,自然数nに対して
> f 0 + f 1 + ... + f n
> を計算する関数とする.

lambda 版 は以下のように作成しました。
sigmaLambda :: (Int -> Int) -> (Int -> Int)
sigmaLambda f = \x -> sum [f i | i <- [0 .. x]]

で、部分適用版ですが、

sigma :: (Int -> Int) -> Int -> Int
sigma f 0 = f 0
sigma f n = sigma f (n-1) + f n

で、いいんでしょうか。
題意のような関数を返すのですが、部分適用という感じがしません。
出題者がどのような回答を期待しているか知りたいのですが。
(あと、なんか lambda版を、内包表現とか使ってて、出題意図に沿ってないような気がするのです)

114:デフォルトの名無しさん
04/04/14 13:37
>>113
> 題意のような関数を返すのですが、部分適用という感じがしません。
addNum'' n m = n + m に部分適用を使ったといっているのだからそれでいいだろう。
sigmaPartial f n = sum [f m | m <- [0..n]]

> (あと、なんか lambda版を、内包表現とか使ってて、出題意図に沿ってないような気がするのです)
それなら使わなければいいのでは?
sigmaLambda = \f n -> if n == 0 then f 0 else sigmaLambda f (n - 1) + f n

115:デフォルトの名無しさん
04/04/14 14:00
sigma,sigma' :: (Int -> Int) -> (Int -> Int)
sigma f = \ n -> foldl (\ s i -> s + f i) 0 [0..n]
sigma' f = let iter s x = if x < 0 then s else iter (s+f x) (x-1) in iter 0

116:デフォルトの名無しさん
04/04/14 14:37
import Control.Monad.Fix (fix) -- fix f = f (fix x)
sigma = flip fix 0 $ \s t f n -> if n < 0 then t else s (t + f n) f (n - 1)

117:デフォルトの名無しさん
04/04/14 14:38
fix f = f (fix f)ね。

118:デフォルトの名無しさん
04/04/19 19:21
Haskell に例外処理の機構はあるの?

119:デフォルトの名無しさん
04/04/19 19:37
ある。
Haskell98でもIOモナドからthrowできる例外(IOError)があるし、
最近のGHC、Hugsでは普通の関数からも例外(Exception)をthrowできる。
catchはIOモナドの中でおこなう。

参照: Control.Exception

120:デフォルトの名無しさん
04/04/20 23:50
Haskell勉強中なんですけど、
「モナドは継続渡しを提供する」という大雑把な理解でいいでしょうか?
・・・違うかな?

121:デフォルトの名無しさん
04/04/24 22:23
なんで Prelude で (!!) は Integer じゃなくて Int で定義されているの?

122:デフォルトの名無しさん
04/04/25 02:07
>>121
実際問題それ以上使うことはないからだろう。
Haskell 98 Report によると maxBound::Int は少なくとも 2^29-1。
(!!)のインデックスは0-originだから、長さ2^29のリストまで扱える。
これ以上の長さのリストを使う場面は……。

123:デフォルトの名無しさん
04/04/25 12:41
円周率の世界記録に朝鮮したい人はどうすれば?

124:デフォルトの名無しさん
04/04/25 18:11
>>123
自分で最低義すれ。

125:デフォルトの名無しさん
04/04/26 14:54
>>123
円周率は全桁保持していなくても次を計算できたはず。

>>124
アドレスの制限があるから多くの計算機と既存の処理系では
再定義しても無駄。

126:デフォルトの名無しさん
04/04/26 23:48
>>120 こんなん見つけた

URLリンク(www.jaist.ac.jp)

ここの資料はjaistのゼミ資料?
他にはHaskellDBが自分的に興味深い.
TorqueとかHibernateなんて目じゃない. Haskellだけど…

127:デフォルトの名無しさん
04/04/27 14:27
>>121
haskell@でもちょうど議論されてるね。
上ででたものの他に、こういう意見があった。

Integer派:
*   Lazyにcreated/destroyedなデータならアドレスの制限を
    受けずに大きいものを利用できるはずだ。
*   Intは一般的なケースへの最適化であり、
    "Premature optimization is the root of all evil."

Integerには反対派:
    Integerにするのは、巨大なリストという特殊な状況への最適化である。
    (Integral b) => がよろしい。

128:デフォルトの名無しさん
04/04/27 18:46
Hanatani さんすげーな。
オレもああいう凄腕Haskellerになりたい。

129:デフォルトの名無しさん
04/04/28 12:39
>>128
なんか凄いもの作ったの?

130:デフォルトの名無しさん
04/05/05 01:32
しばらく見ないうちに「関数型言語」のスレがひどいことになってるな。


131:デフォルトの名無しさん
04/05/05 02:34
>>130
Aranskさま~~早くこのスレにも御光臨してくださいませ~~
Aranskさま~~早くこのスレにも御光臨してくださいませ~~
Aranskさま~~早くこのスレにも御光臨してくださいませ~~
Aranskさま~~早くこのスレにも御光臨してくださいませ~~
Aranskさま~~早くこのスレにも御光臨してくださいませ~~

132:デフォルトの名無しさん
04/06/27 22:34
たま~にはあげてみる

Haskell Support for the Eclipse IDE
URLリンク(eclipsefp.sourceforge.net)

0.3.0はEclipse最新var.(M9~正式版)に対応しているぞ。

133:デフォルトの名無しさん
04/06/30 18:10
おお. しかしスクリーンショットがほしい所かも. 後でインスコしてみるか…

Fudgets
URLリンク(www.cs.chalmers.se)

触ってる人いる? これから弄ってみようと思うのだけど.

featureのページに,
Declarative flavour. While it is possible to enable GUI programming in
a functional language by providing an interface to an imperative GUI toolkit and,
in effect, using an imperative sub-language within the functional language,
Fudgets provide a declarative style of programming also for the construction of GUIs.

とある. なんだか期待大.

134:デフォルトの名無しさん
04/06/30 20:48
>>133
使えたら是非おしえてくれ。
Declarative GUI toolkitって数年前から
どれもメンテが止まってるっぽいんだよな。

最近ではwxHaskellがスタンダードになりつつあるけど、
やっぱりHaskellならDeclarativeにやりたい。

135:デフォルトの名無しさん
04/07/17 08:42
Haskell Marathon
URLリンク(www.sampou.org)

136:デフォルトの名無しさん
04/07/18 09:25
Haskell で Marathon を実装するのかとオモタ。

137:デフォルトの名無しさん
04/07/26 01:14
マラソン参加してみようかな。入門ページ読んだくらいで準備はよいだろうか

138:デフォルトの名無しさん
04/07/29 09:20
マラソン直前に台風直撃の悪寒

139:デフォルトの名無しさん
04/08/09 23:33
LL WeekendでのHaskellに対する聴衆の感想は「Haskellのコードはよくわからない」というのが多かったみたいでつね

140:デフォルトの名無しさん
04/08/10 01:19
5分だか7分だかでわかれという方が無理があるという話がある。発表者陣はよ
くやったと思うよ。
「わたしはもうループも書けなくなってしまって……」というのにワロタ。

141:デフォルトの名無しさん
04/08/11 02:33
LL侍はHaskellを斬ったの?

142:デフォルトの名無しさん
04/08/12 01:39
>>141
「Hello, worldもブラックボックス斬り」されてました。

143:デフォルトの名無しさん
04/08/12 13:41
おれはhaskell haskell haskellだ
関数型の haskellだ
短くて 簡潔で 理解しやすいコードを書けるぜ
って、言うじゃない

だけど
難しくて monad が理解できませんから

残念!
「Hello worldさえブラックボックス」
斬り

144:デフォルトの名無しさん
04/08/12 20:55
むしろHello, worldだから難しいような気がする


145:デフォルトの名無しさん
04/08/12 21:58
main = do putStr "Hello, World!"

で済むから、コード自体は特に難しくは見えない。
ただ、入門者が Hello, World に到達するまでの過程が難しいんだよね……。


146:デフォルトの名無しさん
04/08/12 22:00
>>145
そのdoはいるの?

147:145
04/08/12 23:13
この場合はいらないけど、先々のことを考えたら入れた方がいいかな、とちょっ
とだけ思ったのです。
main = do str <- getLine
putStr str
みたいに。


148:デフォルトの名無しさん
04/08/13 07:57
いきなりIOから入るのがまずい。
fact→fib→qsortあたりから入れば
得体の知れないモナドをとりあえず回避できる。

149:デフォルトの名無しさん
04/08/13 16:25
再帰とリスト処理しかできないHaskellちゃん
がんばってもせいぜい二分木

150:デフォルトの名無しさん
04/08/13 17:34
膣門です。
"Hindley-Milner" って、何て読むんでつか?


151:デフォルトの名無しさん
04/08/14 01:49
誰か「モナドだけで書く Haskell プログラミング」を書いてくれい

152:デフォルトの名無しさん
04/08/15 13:29
>>151 Cでも使ってれば?

153:デフォルトの名無しさん
04/08/15 21:34
そういやHaskellのコンパイルはC経由なんだよね

154:デフォルトの名無しさん
04/08/15 22:04
末尾再帰の保証とかC経由じゃ無理だろ

155:デフォルトの名無しさん
04/08/15 22:21
GHCで最適化オプション付けるとCのコード吐くんじゃなかったっけ?

156:デフォルトの名無しさん
04/08/16 02:59
>>150
メール出して聞いたら?
URLリンク(www-maths.swan.ac.uk) J. Roger Hindley
URLリンク(www.cl.cam.ac.uk) Robin Milner

157:デフォルトの名無しさん
04/08/16 05:57
>>156
もちつけ

158:デフォルトの名無しさん
04/08/16 06:12
>>154
そりゃ当然、Cにする前にプログラム変換するだろ
それに大抵のCCには-foptimize-sibling-callsみたいなのがあるだろうし

159:デフォルトの名無しさん
04/08/16 08:24
レベル低いな。っつってもHaskellのことは何も知らないのであれなんだが。。。
ユーザーレベルで言語をマスターするっつーのは、ある処理系を骨までしゃぶり
尽くすことだろ。リスパーのように自作こそ最強だが、複雑な言語ではそこまでは
まあ、なかなか出来るもんでもないしな。
GHCのことについて詳しい奴がいないのを見ると、誰もHaskellでまともに
プログラム書こうとしてないように見える。結局おまいらは、話のネタに
関数型言語を選んでるだけなんだよ。

160:デフォルトの名無しさん
04/08/16 23:20
↑Aransk?

161:デフォルトの名無しさん
04/08/17 00:31
Simon Peyton Jones は C-- もやってるのに、自前でオプティマイズ出来ないってのは意外。

162:デフォルトの名無しさん
04/08/17 00:50
>160
Aranskはいちゃもん言うだけでプログラムすら書かんだろ?

163:デフォルトの名無しさん
04/08/18 12:47
wxhaskellについてですが、
サンプルプログラムのBouncingBalls.hsでセグメンテーションフォールトが
起きます。(URLリンク(wxhaskell.sourceforge.net))
プログラムを起動し、'p'などのアルファベットを入力することで生じます。

そこで小さなプログラムを作って試してみたのですが、
やはり同様な現象が起ります。

$ cat test.hs
import Graphics.UI.WX

main :: IO ()
main = start test

test :: IO ()
test = do f <- frame []
p <- panel f []
set f [layout := widget p]
set p [on(charKey 'a') := print "test ok"]
$ ghc -package wx test.hs -o test
$ ./test
(ここでキーボードの'a'を入力)
セグメンテーション違反です

環境
wxhaskellのバージョンは0.7
wxGTKのバージョンは2.4.2
OSはlinux

他の環境でもこのバグが再現するでしょうか。

164:デフォルトの名無しさん
04/08/19 17:20
>>163
特に問題発生せず

環境
wxHaskell 0.8
wxWidget 2.5.2
MacOS X 10.3

$ ghc -package wx test.hs -o test
$ /usr/local/wxhaskell/bin/macos-app -v test

できたtestをFinderからダブルクリックで起動
真っ白いパネルが出てくる
'a' 押すと「コンソール」に "test ok"

とりあえずバージョンアップしてみれば

165:デフォルトの名無しさん
04/08/22 09:05
wxHaskellを0.8にバージョンアップしたら問題は解決しました。
どうもありがとうございます。

166:デフォルトの名無しさん
04/08/22 09:36
このような関数はどう書けばいいんでしょうか?

f (+) [1 2 3] [4 5 6] => [5 7 9]

167:デフォルトの名無しさん
04/08/22 11:30
f g (x:xs) (y:ys) = (g x y) : f g xs ys

168:デフォルトの名無しさん
04/08/22 11:41
f g xs ys = [g x y | (x, y) <- zip xs ys]

169:デフォルトの名無しさん
04/08/22 11:55
これを拡張したn引数(n階?)の関数とn個のリストをとる
関数はどう書くのがいいでしょう。

f n g [x11, x12, ...] [x21, x22, ...] ... [xn1, xn2, ...]
=> [(g x11 x21 ... xn1), (g x12 x22 ... xn2), ...]

みたいな。lispのmapってこんな感じですよね。あちらは
関数のarityがわかるからnは不要ですけど。


170:デフォルトの名無しさん
04/08/22 12:19
f g = map (hoge g) $ zip
Haskellはよく知らんので、hogeをどうやって書くのか調べてもよく分からん。

171:デフォルトの名無しさん
04/08/22 16:24
引数の数が可変ってhaskellでは書けないような気が。
何か方法あったっけ?

172:デフォルトの名無しさん
04/08/22 16:45
>>166

zipWith (+) [1, 2, 3] [4, 5, 6]

173:デフォルトの名無しさん
04/08/22 17:19
>>171
別に可変個の引数は必要ない。
1引数の関数のリストと引数のリストを受け取って適用して返す演算子をつくればOK。
演算子をxとすると
[f, f, f] x [x11, x12, x13] x [x21, x22, x23]
とか。Haskellの細かい文法知らんのでこう書けるかどうかは知らないけど。


174:デフォルトの名無しさん
04/08/22 17:48
どういう型になるんだ?

175:デフォルトの名無しさん
04/08/22 17:53
map sum $ transpose [[1,2,3],[4,5,6],[7,8,9]] => [12,15,18]

こんなもんでどうでしょうか。

176:デフォルトの名無しさん
04/08/22 20:04
>>174
[a->b]->[a]->[b]かな?


177:デフォルトの名無しさん
04/08/22 20:10
zipWith ($)

178:デフォルトの名無しさん
04/08/22 20:54
Prelude> (zipWith ($)) (map (+) [1,2,3]) [4,5,6]
[5,7,9]

ナルホド。


179:デフォルトの名無しさん
04/08/23 11:43
只の関数適用(f x)と(f $ x)って何か違うところあるの?
それとも( )じゃワケがわからないから($)と書けるように
目に見える演算子として用意されているだけ?


180:デフォルトの名無しさん
04/08/23 12:19
$ は関数合成では?

181:145
04/08/23 12:35
関数合成は . でしょ。
>>179 何も代わらない。関数適用のための演算子だから。
本来の利用法は >>178 みたいなものなのかな(個々の要素にそれぞれ適用する
ためには、関数適用の演算子があると便利)。

f $ g x と書くと、演算子の優先度の関係上 f(g x) と同じことになるので便
利、ついでに結合性の関係で f $ g $ h x とか書ける、というのが個人的に
は嬉しい。カッコの省略にも使える。
関数合成はあくまで関数の合成の演算子なので、 f . g . h x とは書けない。
(f . g . h) x なら書けるけど。

182:デフォルトの名無しさん
04/08/23 16:17
可変個数の zipWith については、

Functional Pearl "Do we need dependent types?"
Daniel Fridlender and Mia Indrika, 2000 J. Functional Programming,
vol. 10, July.

URLリンク(www.cs.chalmers.se)

に載っているので興味があるひとは読んでみるべし。


183:デフォルトの名無しさん
04/08/24 12:40
>>171-181
> 只の関数適用(f x)と(f $ x)って何か違うところあるの?

ある。$はただの関数だから、引数の型がそこで固定される。
f :: a -> (forall b. b -> b) -> a
f x g = g x

とすると、f 0 id はOKだが、f 0 $ id はだめ。
ST Monadなんかをつかっていると結構引っかかる。

184:デフォルトの名無しさん
04/08/24 14:37
-- zipWithN
infixl 2 <$>
infixl 1 <->
(<$>) = map
(<->) = zipWith ($)
-- 例
-- (\x y z -> x + y + z) <$> [3,4] <-> [5,6] <-> [7,8]

----------------------------
-- 可変引数 
ncat :: NCat b => b
ncat = ncat' id 
class NCat a where
  ncat' :: (String -> String) -> a
instance NCat String where
  ncat' f = f ""
instance NCat b => NCat (Char -> b) where
  ncat' f x = ncat' (f . (x:))

-- 例
-- ncat 'a' 'b' 'c'

# >>183の171は179の間違い。

185:デフォルトの名無しさん
04/08/24 14:38
>>184
型指定が要った。
ncat 'a' 'b' 'c' :: String

186:デフォルトの名無しさん
04/08/24 20:08
携帯から読むと AA 判定されててワラタ >>183-185

187:デフォルトの名無しさん
04/08/26 20:44
AA的プログラミング

188:デフォルトの名無しさん
04/08/26 20:54
(--#) とか (*^-^*) とか?

189:デフォルトの名無しさん
04/08/30 23:20
Categories for the Working Mathematician の訳書ってなんていうタイトルでつか?

190:デフォルトの名無しさん
04/08/30 23:27
スマソ。
「そのうち出る」 = 「そのうち出版される」という意味か。
「テキストの候補に挙がる」ではなく。

191:デフォルトの名無しさん
04/08/31 00:44
誤爆にも程があります

192:デフォルトの名無しさん
04/08/31 12:01
「数学に勤しむ貴方のための圏論」てのがそれらしいが
近刊とあってまだ出てないようだ。

URLリンク(www.kyoto-su.ac.jp)

193:デフォルトの名無しさん
04/09/07 17:30
末尾再起すると、遅延評価されないですね。
(length (hoge xx yy zz)) < 3
とかで困る。かも。

194:デフォルトの名無しさん
04/09/07 20:50
>>193
> 末尾再起すると、遅延評価されないですね。
そんなことはない。

> (length (hoge xx yy zz)) < 3
> とかで困る。かも。
lengthがstrictだからhogeがlazyでも意味がないとはいえるが、
末尾再帰とは無関係なので、意味がわからない。

なにを誤解してるのですか?

195:デフォルトの名無しさん
04/09/08 10:49
>>193
『末尾再帰の最適化』をすると遅延評価できない(或いはその逆)、のことを言いたいのかな。
それだったら解る。

あ、でも例 (length (hoge xx yy zz)) < 3 の意味はやっぱりわからない。

196:デフォルトの名無しさん
04/09/08 18:24
>>195
> 『末尾再帰の最適化』をすると遅延評価できない(或いはその逆)、のことを言いたいのかな。
詳しく説明きぼんぬ。
gotoでジャンプするコードにするとサンクが作れないのかな?

197:デフォルトの名無しさん
04/09/09 23:56
>>195

take n 末尾再帰関数(無限リスト)

みたいなのが出来ないということでは?

198:197
04/09/10 00:26
括弧の位置を間違えた。
take n (末尾再帰関数 無限リスト ・・)
です。

199:193(初心者)
04/09/10 16:18:42
すいません。どっかいってました。
>197さんの言うとおりです。
例は適当にかいたらだめでした。

200:デフォルトの名無しさん
04/09/10 16:25:19
>>197-198
なにができないと?
take' 0 xs = xs
take' n (x:xs) = take' (n - 1) xs 

take n (take' 10 [0..])

201:197
04/09/10 21:59:52
>>200
返値も無限リストの場合です。

nub0 :: Eq a => [a] -> [a]
nub0 = nub0' []
nub0' l [] = l
nub0' l (x:xs)
  | elem x l = nub0' l xs
  | otherwise = nub0' (x:l) xs

take 10 (nub0 [1..])

202:デフォルトの名無しさん
04/09/10 22:16:02
>>201
nub0 [1..]自体がbottom(無限リストではない)なんだから
末尾再帰も糞もないですよ。

nub0' :: [Int] -> Int
nub0' = foldr (+) 0
だって同じこと。

203:197
04/09/10 23:25:33
いろいろと書き方がまずくてすみません。

nub0 を末尾再帰で定義したから、nub0 [1..] が
bottomになったわけで、Hugsでの定義の

nub l = nub' l [] where
 nub' [] _ = []
 nub' (x:xs) ls
  | x `elem` ls = nub' xs ls
  | otherwise = x : nub' xs (x:ls)

のようにすれば nub [1..] は無限リストになる、という意味です。

204:デフォルトの名無しさん
04/10/07 21:01:01
いいかげん誰かモナドをわかりやすく説明してくんない?
関数型言語のキモは副作用とのコラボレーションなんだし

205:デフォルトの名無しさん
04/10/08 02:06:46
>>204
URLリンク(www.sampou.org)
ではだめ?

206:デフォルトの名無しさん
04/10/14 01:54:56
んじゃ自分の理解度の確認を兼ねて。(突っ込みよろしく)

モナドは数学上はモノイドといって単位元を持つ半群のこと。
一応簡単な説明。
(X * X ) * X = X * ( X * X ) といった「結合側」が成り立つ演算*があって
(E * X ) = ( X * E ) = X となる単位元Eを持つようなXのこと。

X が整数だとすれば * は足し算 E は 0
もちろん * を掛け算 E は 1としてもいい。
* を文字列の結合 , Eを空文字列 "" とすれば文字列もモノイドとみなせる。

で、HaskellのIO型には
上の文字列モナド(モノイド)の1文字づつの代わりにOSのシステムコール呼び出しの機械語が
入っていると思えばいい。

IOモナドA( [キー入力] ) >> IOモナドB( [画面出力] )  を適用すると 
  IOモナドC( [キー入力]の次に[画面出力] ) になる

みたいな。
で どんどん >> や >>=で繋いでいくわけ。

もちろん結合則も成り立つ。
ちなみにreturn 関数が返すIO型が単位元になってる。

これはreturnの返すIOには何もシステムコール?が含まれてないから
上の文字列モナドの空文字列みたいな感じ

これで宜しいでしょうか>>204

207:デフォルトの名無しさん
04/10/14 03:55:12
>>206
Monoidだと思って話すなら:

結合法則: (a * b) * c = a * (b * c) を満たす演算*が定義されていて、
単位元 e (e * a = a * e = a をみたす) を持つような集合を
Monoid(以下、単に半群という)といいます。
例えば"行列"や"微分方程式の解作用素"は半群になっています。

*** Point(1): a * b /= b * a。順序は変えられない

この半群の集合への作用(注1)の仕方を定めたものがMonadです。
return == e で、あとは * にあたるものが >>= となります。
そういうと、return :: a -> M a (M "a" なのは単位元だから) なんだから、
>>= :: (s -> M t) -> (t -> M u) -> (s -> M u) 
じゃないのかと思うかも知れませんが、
>>= :: M t -> (t -> M u) -> M u
でもいいのです。
というのは、(c * d)' x = c' (d' x)なので、*を決めることと、
M sの任意の元(d' x 等)をどこにうつすかを決めることは同じことだからです。

続く。

208:207
04/10/14 03:57:32
この行は前のメッセージの最後にあるべきでしたが、

*** Point(2): x /= y ならば a' x と a' y は等しくなくてもよい


さて、例えばIOモナドなら、putStr :: String -> IO () 
は上のaやらbやらにあたります。ではgetLine :: IO Stringはというと、
元を一つしか持たない集合をUとしてgetLine :: U -> IO String の省略記法
なのです。元が一つしかないのだから、わざわざU->を考える必要はありません。

Point(1)、(2)がIOの、順序を変えられない、毎回違う答えが帰るかもしれない
という性質を満足させてくれます。

main = getLine >>= putStr は、(putStr * getLine) と同じもので、
実行するのは putStr' (getLine' world) を計算することです。
getLineが毎回異なる文字列をputStrに>>=で与えても、それはworld
が違ったからだと思えばなにも問題はありません。

*1 (作用)
    行列をベクトルにかけるとベクトルができますが、これと同じように、
    半群(M)の元(a, b, ..)をある集合(S)の上の関数とみなすことができます。
    好き勝手に関数とみなすのではなく、次の性質をみたすとき、
    半群MがSに作用している、ということにします。関数とみなすときには'をつけます。
    (a * b)' x = a' (b' x) (x は S の元)
    
# monoidとmonad (triple)はどちらも数学の概念で、似ていますが別物です。

209:デフォルトの名無しさん
04/10/14 08:51:55
(X * X ) * X = X * ( X * X ) といった「結合側」が成り立つ
の()の意味はなんだ?
単に型が合うかどうかか?演算の時間的な順番か?

210:デフォルトの名無しさん
04/10/14 09:25:14
>>209
演算の順序。
代数の本を読めばどしょっぱなに書いてあるよ。

211:デフォルトの名無しさん
04/10/14 09:29:17
じゃあ(入力 * 出力)* 入力 = 入力 * (出力 * 入力)になって
最初に出力してくれるのかい?

212:デフォルトの名無しさん
04/10/14 11:05:33
コードの結合順序と、実行順序を混同するな。

Cで {{f(); g();} h();} と {f(); {g(); h();}} が同じ結果になる
みたいなものだ。

213:デフォルトの名無しさん
04/10/14 15:33:35
だから(X * X ) * X = X * ( X * X )ってのはどういう意味なの?

214:デフォルトの名無しさん
04/10/14 16:42:30
>>213
モノイドの説明だとしたら、その式はそうとしか言えないのでは。整数上の加
算について考えると、
(1+2)+3 = 1+(2+3)
が結合則。
1+0 = 0+1 = 1
が単位元の性質ということ。数学の話だよ。

モナドだとすれば、 >>207-208 じゃないのか。
(f * (g * h)) x = ((f * g) * h) x = f(g(h(x)))
という風に理解したんだがこれは当ってる?

Haskell の記法を使えば、
x >>= (\x -> x >>= h >>= g) >>= f = x >>= h >>= (\x -> x >>= g >>= f)
かな?

モナドというのは、「評価の順序を保証するもの」という風に考えているんだ
が、その事を「結合則は成立するが、交換則は成立していない」という事で表
現しているということなのでは。

副作用の話は 208 の方に書いてあると思うんだが、こっちはよくわからない……。


215:デフォルトの名無しさん
04/10/14 17:00:35
>>214
> 「結合則は成立するが、交換則は成立していない」
「交換則は必ずしも成立するわけではない」のほうが適当では?

216:デフォルトの名無しさん
04/10/14 17:05:38
この場合の(X * X ) * X = X * ( X * X )の意味は
どういう風に括弧をつけても関数Xの適用順序は
左から右、右から左と一定であるって意味でいいの?

217:デフォルトの名無しさん
04/10/14 17:17:39
>>215
ああその通りですね。失礼しました。

>>213=216
まあその通りといえばその通りではないかと思います。
*を関数の合成みたいな演算だと考えればよいのでは。


218:デフォルトの名無しさん
04/10/14 17:22:34
で、208に質問なんですが、

> *** Point(2): x /= y ならば a' x と a' y は等しくなくてもよい

はわかるとして、 GetLine :: U -> IO String であり、 U が一点集合なのだ
としたら、これは x = y である(にもかかわらず a' x /= a' y になりうる)
例のように読めてしまったのですが、どこで間違えているんでしょうか?

getLine' world というのは、常に world が与えられるが、 world が毎回異
なるので返り値が異なることがあるっていうこと? でもそれって一点集合な
んでしょうか?

219:デフォルトの名無しさん
04/10/14 17:26:23
結合法則は分かったが

*** Point(1): a * b /= b * a。順序は変えられない
*** Point(2): x /= y ならば a' x と a' y は等しくなくてもよい
Point(1)、(2)がIOの、順序を変えられない、毎回違う答えが帰るかもしれない
という性質を満足させてくれます。

っていうのは普通の関数とどこが違うの?
普通の関数でもそういうのあるんだから、
モナドとかいわずに普通の関数と一緒に扱えばいいじゃない。

220:デフォルトの名無しさん
04/10/14 17:33:16
x = yでもa' x と a' yは等しくなくてもいいんじゃない?

221:デフォルトの名無しさん
04/10/14 17:50:24
結合法則は満たすけど交換法則は満たさないって状況、
小学校でやる一般的な算数にある?

222:デフォルトの名無しさん
04/10/14 17:52:51
引き算、割り算

223:デフォルトの名無しさん
04/10/14 18:00:53
結合法則満たすのか?

224:デフォルトの名無しさん
04/10/14 18:01:04
perl -e '$op="-"; print eval "4 $op (3 $op 2)"'
perl -e '$op="-"; print eval "(4 $op 3) $op 2"'
これ、答えが違っちゃうけど、、なんか間違ってます?

225:デフォルトの名無しさん
04/10/14 18:16:35
>>219
> っていうのは普通の関数とどこが違うの?
> 普通の関数でもそういうのあるんだから、

どこの世界の関数だそれは(w


226:デフォルトの名無しさん
04/10/14 18:23:24
べき乗とかなら交換したら意味がちがうし
x /= y ならば a' x と a' y は等しくないんちゃう?

227:デフォルトの名無しさん
04/10/14 18:27:33
もちつけ。モノイドがモナドなわけじゃないぞ。
> この半群の集合への作用(注1)の仕方を定めたものがMonadです。

228:デフォルトの名無しさん
04/10/14 18:29:58
>>219
逆で、関数でそういう性質が成り立って、文字列の連結や状態遷移でもそういう性質が成り立つからそれらを抽象化してモナドにしたってこと。
連結リストや配列リストの性質を抽象化してリストとして扱うようなのと同じ。

229:デフォルトの名無しさん
04/10/14 18:31:50
じゃあ普通の関数もモナド?

230:デフォルトの名無しさん
04/10/14 18:42:39
>>220
x = y で a' x = a' y でなくても構わないっていうのは数学的にはおかしい
気がしますが。
プログラム的には副作用が起きているなら成立すると思いますが、その副作用
を上手く扱うのがモナドなんじゃないの?

231:デフォルトの名無しさん
04/10/14 18:54:09
順序は正しく守って、毎回違った答えが出ても
処理系はエラーを出さず理論的にもきちんとまとめられるってことか?

232:207
04/10/14 19:02:54
>>218
そうですね。すみません。208は全然ダメです。 
モナドをモノイドで押し切ろうというのは無理がありました。

233:デフォルトの名無しさん
04/10/14 19:03:15
>>229
普通の関数だと、たとえば
f(g(x), h(y))
がどの順番で評価されるかは不定。でも、モナドを使えば、その順序を確定さ
せることができる。

……副作用とかいう話じゃなくて、順序を確定させることが重要なのかなあ。
順序が確定的だから、副作用が起きるコードでもOKみたいな感じ?

234:デフォルトの名無しさん
04/10/14 19:06:11
モナドってのは何をさすんだい?
a * bだったらaやbがモナド?それとも*がモナド?

235:207
04/10/14 19:15:28
>>233
順序と、引数返り値に直接アクセスできないところが味噌です。
type IO a = world -> (a, world)
なら、main world0 = let (s, world1) = getStr world0 in print s world0
とかやってしまえないようになるところ。

>>234
a, bと*の組みです。
行列群が、行列と行列のかけ算の両方がないと考えられないのと同様に。

236:デフォルトの名無しさん
04/10/14 19:18:35
a,bはプログラム中の式
*は各式の関係を表す演算子

237:207
04/10/14 19:27:09
>>232 自己レスもちろん>>207もだめです。
モナドは雰囲気はモノイドなんですがやっぱりモノイドとは
みなせそうにないので、これも嘘です。
> この半群の集合への作用(注1)の仕方を定めたものがMonadです。
予想と違って、正しいかもしれないものだと素直に読んだ方が
多かったようで、申し訳ないです。

238:デフォルトの名無しさん
04/10/14 19:31:13
理解した部分だけ書くと、結合法則を満たす関数の合成を使うと
IOのような実行の順序が重要な意味をもつ関数を(順序不定で)合成しても
合成された関数は一意的な順序でIOが実行される関数になるということか?

順序を保つ合成が結合法則を満たすのは分かったが、
結合法則を満たす合成は全て実行の順序を保つでいいのか?

239:デフォルトの名無しさん
04/10/14 21:14:39
>>238
順序不定には合成できないから、明示的に順序をつけることを強制できる。

putStr (getLine, [getChar])
でなく
getLine >>= (\s -> getChar >>= (\c -> putStr (s, [c])))

getChar >>= (\c -> getLine >>= (\s -> putStr (s, [c])))

240:デフォルトの名無しさん
04/10/14 21:26:54
じゃあモナドは実行の順序が決められてる関数の中の一つってことか?

241:デフォルトの名無しさん
04/10/14 21:57:19
例えば左から右へ順番に実行する関数hogeが定義できて、
hoge getLine getCharから
getLine >>= (\s -> getChar >>= (\c -> putStr (s, [c])))と
同じ動作を定義できるのか?

242:デフォルトの名無しさん
04/10/15 01:54:14
>結合法則を満たす合成は全て実行の順序を保つでいいのか?

これは成り立たないと思う。

モナドの結合法則の概念と順序は本来関係ないんじゃないかな。
たまたま順序を組み立てるのにモナドが使えるってだけだと思う。

URLリンク(www.sampou.org)
↑のListモナドとかは
順序とは関係なさそうだし。(関数から複数の遅延込みの非正格値を返すためのもの?)
モナドの用途は順序の決定のみにあらずってとこか。

243:デフォルトの名無しさん
04/10/15 04:12:02
>>241
hoge :: IO String -> IO Char -> IO ()
hoge f g = f >>= \s -> g >>= \c -> putStr (s, [c])

getLine :: String、getChar :: Char だったら無理。

244:デフォルトの名無しさん
04/10/15 04:13:08
>>242
> List モナドは非決定性をもつ計算の連鎖を、演算をそれぞれのステップで可能なすべての値に適用することで、合成する戦略を内包しています。
だけなら、モナドでなくてもいいね。
------------
module MList where

data MList a = a :*: (MList a) | MNull deriving (Eq, Show)
infixr 3 :*:


instance {- Broken -} Monad MList where
  (x :*: xs) >>= f = merge (f x) (xs >>= f)
    where 
      merge (x :*: xs) ys = x :*: merge ys xs
      merge MNull ys = ys
  MNull >>= f = MNull
  return x = x :*: MNull
  fail s = MNull

toMList xs = foldr (:*:) MNull xs

(>=>) = (>>=) -- 2ch : ">> が多すぎます!"
(>=>) :: Monad m => m a -> (a -> m b) -> m b
test f = test1 f == test2 f
test1 f = f [1,2] >=> \x -> f [3, 4] >=> \y -> f [5, 6]
test2 f = (f [1,2] >=> \x -> f [3, 4]) >=> \y -> f [5, 6]

245:デフォルトの名無しさん
04/10/15 08:50:04
そうだよなあ。
モナドが「暗黙の引数world」と「関数のeagerな評価」を意味するだけなら,結合法則はなくてもよい。

246:デフォルトの名無しさん
04/10/15 11:05:46
IOモナドについて。
話の流れから多少それるのかもしれませんが、
IOモナドの僕のとらえかたは以下のような感じです。

putStrはStringを引数としてとり、
「その文字列を表示する動作」を返す関数。
であり、putStr "Hello " >> putStr "World"
とした場合、putStr "Hello "とputStr "World"のそれぞれが評価される
順番は問題ではない。
putStr "Hello "が評価された時点では、
"Hello "は出力されずに、「"Hello "を出力する動作」が
決定するだけである。
そして、putStr "Hello " >> putStr "World"は、
"Hello "を出力した後に"World"を出力する動作として評価される。
この時点では何の出力も生じない。
この動作は、main = ...というように、mainに代入されることにより、
評価器とは切り離された装置によって出力に変えられる。

つまり、putStr "Hello " >> (putStr "World" >> putStr "\n")
とした場合、putStr "World >> putStr "\n"の部分が先に評価されて、
「"World"を出力した後に、"\n"を出力する動作」となり、
その後に、putStr "Hello "と結び付けられて、
「"Hello "を出力した後に「"World"を出力した後に"\n"を出力」する動作」
となる。
これは、
「「"Hello "を出力した後に"World"を出力」した後に"\n"を出力する動作」
と等しい。

247:デフォルトの名無しさん
04/10/15 12:01:44
>>246
ありがとう、やっとすっきりした。
つまり継続を渡しているわけね。


248:デフォルトの名無しさん
04/10/15 12:14:00
>>246
> であり、putStr "Hello " >> putStr "World"
> とした場合、putStr "Hello "とputStr "World"のそれぞれが評価される
> 順番は問題ではない。

順番は問題。これは左から評価しないと(されるように>>が定義されてないと)、
putStr "Hello ">> error "Error." 等が正しくうごかない。

> この動作は、main = ...というように、mainに代入されることにより、
> 評価器とは切り離された装置によって出力に変えられる。

上とも関連して、出力しながら内部の式を評価するわけで、
評価し終わったものを実行するのでは「ない」のだから、
 main world を評価すると考えるほうがいいのでは。

上で自分でもただStateモナドのようにかいてしまったけれど、
IO a = World -> (a, World) {- ただしStrict -} と思うことにして。 

(正則性と関連して実はIOはモナドの結合法則を満たしていなかったような)


> つまり、putStr "Hello " >> (putStr "World" >> putStr "\n")
> とした場合、putStr "World >> putStr "\n"の部分が先に評価されて、

ここも左から評価される。

あとは大体OKと思う。

249:デフォルトの名無しさん
04/10/15 17:24:40
>>248
>順番は問題。
>>256
> putStrはStringを引数としてとり、
>「その文字列を表示する動作」を返す関数。
という前提だからいいんじゃないの?


250:デフォルトの名無しさん
04/10/15 18:08:50
>>249
putStr "Hello " >> error "Error." 
の右辺を先に評価したら"Hello"が表示される前にerrorで終わってしまうでしょ。

正格性解析かなにかで>>の左辺と右辺が
Strictにしかも_|_にならずに評価できると知っていたら
何かの気まぐれで右辺から評価するかもしれないけど、基本は左から。

ちなみに右から(Lazyに)評価したら末尾再帰も無意味になるし無限ループも書けない。

251:デフォルトの名無しさん
04/10/15 20:36:06
ちなみに右から(Lazyに)評価したら末尾再帰も無意味になるし無限ループも書けない。
どういう意味だ?

252:246
04/10/15 21:53:07
評価という言葉を誤用したみたいです。

putStr "Hello " >> putStr "World"は、
"Hello "を出力する動作の後に、"World"を出力する動作を続けた動作と解釈される。
と言いかえるべきなのかな。

(1+3) : []を、(4ではなく)1+3を空のリストに加えたものと解釈される。
というのと同じで、この1+3が4になるのはmainに関連づけられたとき
(とhugsなどで、返り値の表示を求められたとき)のみである。

つまり、putStr "Hello " >> putStr "World"が左から評価されるのは、
print ((1+2):(2+3):[])が左から評価されるのと同様、
値が必要になった時点で評価されるという、遅延評価の性質から理解できる。

print ((1+2):(2+3):[])でまず1+2が、つぎに2+3が評価されるのは、
(:)に左から順に評価するという性質があるのではなく、
必要とされるのが1+2のほうが先であるというためである。
これは、print $ reverse ((1+2):error "foo":(2+3):[])の出力が[5,となる点からも確認できる。

それと同様にputStr "Hello " >> putStr "World"が左から評価されるのは、
まずputStr "Hello "がプログラムの実行に必要とされ、その後にputStr "World"が必要とされるためであり、
(>>)が左から評価されるといった性質を持っている必要はない。

(しかし、(>>)の右側が左側よりも先に必要とされるという状況は考えられないので(>>)が左から評価される性質を持つというのは
そんなに間違いではないかもしれない。)

putStr "Hello " >> error "Error."がうまく評価されるのも同様で、
"Hello "の出力の際にはerror "Error."を評価する必要がないためである。

現時点での僕の解釈ですので、間違いもあると思います。
Haskellに積まれた概念は非常に興味深いので、
今後も熟考していこうと思っています。

253:デフォルトの名無しさん
04/10/15 23:06:59
どうも隔靴掻痒の感があるな。
モナドの表示的意味は言語仕様に書いてないのか?

[| >> |]ρσ = ...?

254:デフォルトの名無しさん
04/10/16 05:09:35
>>252
いったいどういう原理によって
> まずputStr "Hello "がプログラムの実行に必要とされ、その後にputStr "World"が必要とされるためであり、
こうなってると思ってるわけですか? 

mainや(>>)は関数じゃなくてなにかすごく賢い"評価器とは切り離された装置"
が何が必要かを見切って必要なところだけ評価するという立場?
それならそれでもいいですが…

私は、State(World)についてStrictなMonadだと思えば、
なぜ(>>)の左が先に必要になったのかが、説明できると書いたわけです。

255:デフォルトの名無しさん
04/10/16 05:13:41
>>251
まず、mainだけ特殊な評価をうけるとは考えないことにします。

右から評価されると無限ループも書けないというのは、
main = loop where   loop =  act >> loop
                    act = print "x"
ここでloopの右辺を先に評価したらact >> (act >> (act >> ..))と
ネストした列ができるだけでloopの処理が進まないという意味です。
末尾再帰も同様のことになります。

先に述べたように、特殊な評価装置や特殊ルールは考えないので、これは、
(>>)がそういう順序に評価を導くように定義されているということを意味します。

単にmainそのものを評価しても、(\_ -> ...)の形か、
(コンストラクタ) ...の形になって...の部分は評価されずに終わります。
これでは...の中に書いてあるIOアクションの列をどう評価、
実行していけばいいかはわかりません。

そこで、mainは関数であって(type IO a = World -> (a, World)、
プログラムの実行とはmain worldを評価する、つまりmain worldの
返り値を求める評価を行うことだと考えることにします。

例えば(putStr "X") worldを評価すると、
"X"が出力されたWorldを返します("X"が出力される)。

256:デフォルトの名無しさん
04/10/16 05:15:13
これは、普通の評価なので、main worldの返り値(a, world)が求まれば
いいので、まず返り値に必要な部分から計算されます。
したがって、遅延評価ならば、a >> bにおいてworldに最後に関与する
「外側」にある"b"のほうから評価が行われるはずだということになります。
これが「右から(Lazyに)」の意味です。

ちろんこれではループも書けないのでIOモナドとしては使えません。
しかし、WorldについてStrictなモナドだとすれば、
左から評価されるようになります。

-- typeではモナドの定義がHaskell98では書けない。
newtype IO a = IO { runIO :: World -> (a, World) }
instance Monad IO where
    ioact >>= f = IO $ \world -> world `seq`
        let (a, world') = runIO ioact world 
        in  runIO (f a) $! world'

もしよくわからなければ、Control.Monad.Stateのlazyなstateモナドで
loopや末尾再帰のプログラムを書いて挙動を観察してみてください。

257:デフォルトの名無しさん
04/10/16 09:30:25
これに基づいて議論しませんか?

URLリンク(www.haskell.org)

258:デフォルトの名無しさん
04/10/16 10:36:55
>>257
基づいてないと?

IOの話なら、規格の性質を満たすIOはいかにして定義され得るか
ということを議論しているつもりなんだけど…

259:もなど初心者
04/10/16 18:27:11
なんかグダグダになってんのか話が進んでるのか判断できないんですが
デバッグ辛くないですか?

260:デフォルトの名無しさん
04/10/16 19:02:57
別に。 > デバッグ辛くないですか?

261:デフォルトの名無しさん
04/10/16 19:06:52
>>257のreportを見る限り,どちらの方法でもIOモナドの外部仕様を満たせるんじゃない?

The >>= operation passes the result of the first operation as an argument to the second operation.

ということなので,f >>= gに対して,fの中で起こる副作用がgの中で起こる副作用より先に起こる
ようにするには,

(1) >>=は,左辺の引数についてstrict
(2) g(正確にはgの中での副作用の呼び出し)がstrict

のどちらでもよい(ように思える).

262:デフォルトの名無しさん
04/10/16 20:00:26
>>261
> どちらの方法でもIOモナドの外部仕様を満たせるんじゃない?
だれが(1)を主張しているの?

> (1) >>=は,左辺の引数についてstrict
f >>= g のfが先に評価されるだけで、actionの実行とは関係ない。
例えば、f >> (g >> (h >> ..)) の無限列ができるだけでactionが実行されない
こともあり得る。

> (2) g(正確にはgの中での副作用の呼び出し)がstrict
なにがいいたいのかよくわからない。
Monadの話をしているのだから>>=の性質について話さないと。
>>255-256理論のことなのかな(そうは読めないけれど)。


それから、IOモナドはこれ
> Special operations (methods in the class Monad, see Section 6.3.6) 
> sequentially compose actions, 
> corresponding to sequencing operators (such as the semicolon) in imperative languages.
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
を要求してるからf >>= gのfが先に評価されるのであって、
>>261の部分からはそうなるとは限らないことに注意。(cf. LazyなStateモナド)

263:デフォルトの名無しさん
04/10/16 20:43:42
俺はHaskellのことは余りしらないんだけど、Haskellの言語仕様も
MLのように表示意味論(操作意味論でもいいけど)でformalに定義
されてるんじゃないの?

色々と仕様の背後にある意図を考えるのもいいけど、まずちゃんとした定義
を出してくれると素人には有難いなあ。言葉の定義も人によって違うみたいだし。
ちなみに

fがstrict <=> f(_|_) = _|_
lazy evaluation <=> λ計算でいうところのnormal reduction

ということでいいの?




264:デフォルトの名無しさん
04/10/16 21:33:21
>>263
> MLのように表示意味論(操作意味論でもいいけど)でformalに定義

IOはどうなんだろ?
URLリンク(citeseer.ist.psu.edu)
# 個人的にはHaskellのコミュニティはそういう文化じゃないと思ってる。
# formalなsemanticsがどうとかで論文書くんじゃなくて、
# 新しい便利なアイディアをどんどん導入して実際に使う。
# informalなsemanticsだけど気にしない、みたいなことがよく書いてあるきがする。
#
# そういうことに興味がないことによる偏見かもしれない。

ググッたらちょっと古い(1996)けどこんなのも
URLリンク(www-fp.dcs.st-and.ac.uk)
> No formal semantics for these I/O primitives is possible at present, 
> because there is no complete formal semantics for Haskell itself.

formalでないと理解した気がしないなら、
Concurrent Haskell (Simon PJ他)の論文でIOのsemanticsは誰かの論文を参照、
みたいなことが書いてあった気がするから、探してみたら。


> fがstrict <=> f(_|_) = _|_
> lazy evaluation <=> λ計算でいうところのnormal reduction
いいんじゃない。ちなみにdataコンストラクタはlifted。

265:デフォルトの名無しさん
04/10/16 22:00:24
normal order reduction ≠ lazy evaluation

266:デフォルトの名無しさん
04/10/16 22:26:55
>>265
等しくはないね。
でもλ計算でいうところのnormal-order reductionをするわけでしょう?

267:デフォルトの名無しさん
04/10/16 22:48:32
どうもありがとう。
Simon Peyton Jones, Andrew Gordon and Sigbjorn Finne. Concurrent Haskell, POPL, 1996.
をざっと見たところ、その辺の詳しい話は

Roy L. Crole and Andrew D. Gordon.
A Sound Metalogical Semantics for Input/Output Effects, CSL, 1994.
Andrew D. Gordon.
Functional Programming and Input/Output, Cambridge University Press, 1994.

を参照と書いてあった。暇なときにみてみよう。
ちなみに"Concurrent Haskell"の論文も結構面白い。IOの話については
下のような記述があった。ご参考…といってもここの人には常識か。

The sequencing combinators, >> and >>=, feed the result state
of their left hand argument to the input of their right hand
argument, thereby forcing the two actions (via the data
dependency) to be performed in the correct order.
...
In principle, then, a program is just a state transformer
that is applied to the real world to give a new world.
In practice, however, it is crucial that the side-effects
the program specifies are performed incrementally, and
not all at once when the program finishes. A state-transformer
semantics for I/O is therefore, alas, unsatisfactory, and
becomes untenable when concurrency is introduced, a matter to
which we return in Section 6.

268:Haskell???なにそれ?食えるの?
04/10/17 01:10:13
【ビギナ】初心者が習うべき言語は? part6【必読】
スレリンク(tech板:494-番)

おい。
Rubyにケチ付けてるこの馬鹿引き取ってくれよ。

269:デフォルトの名無しさん
04/10/17 01:41:49
ほっといてやれ

270:食べられません。
04/10/17 01:47:28
>>268
> Rubyにケチ付けてるこの馬鹿引き取ってくれよ。
事実誤認だよ。

>>269
ありがとう。

271:デフォルトの名無しさん
04/10/17 03:02:52
>>265
normal reduction = leftmost reduction = lazy reduction
じゃなかったっけ



272:デフォルトの名無しさん
04/10/17 03:09:20
eager evaluation と call-by-value が対応して
lazy evaluation と call-by-need が対応して

normal-order reduction というと call-by-name が対応するといいたいんじゃない?

273:デフォルトの名無しさん
04/10/17 11:45:11
>> 254
> なにかすごく賢い"評価器とは切り離された装置"
が必要性を判断してくれると仮定しなければ、
print $ [3, 1+2, 4] !! 0
で1+2が評価されない理由は説明できないと思う。
具体的にはその装置はHaskellの一部であって、
Haskellプログラムの内側では議論できない実装に近い部分の話になって
くるんじゃないかな。

>>255,>>256のような議論は有意義だと思うが、
上述したような「装置」によって、(:)と(>>)を同列に扱えるのであり、
(:)にその「装置」が必要とされている以上、
(>>)に他の特別な理論をあてはめるよりは、
必要に応じて評価される。という
lazy evaluationの原則を単純にあてはめればすむのではないかと思う。

ちなみに、
IOというものは[](リスト)と同様にそこにある何かであり、
たとえばputStrLn "Hello"が実行されると"Hello"を出力するのは、
[1,2,3]が(!!1)で2を返すのと同様にとらえられるのではないだろうか。

IOは評価時点では出力されずに、実行という次のステップで出力が生じる。
これは、
main = putStr "Hello " `seq` putStrLn "World"
での出力が
World
であるという点からも理解されるのではないだろうか。

HaskellのIOでは評価と実行は切り離されている。ということに今日気付いた。

274:デフォルトの名無しさん
04/10/17 13:33:11
「評価する」というのと「印字する」というのが微妙に混同されているような、いないような。

275:デフォルトの名無しさん
04/10/17 14:12:57
>>274
> print $ [3,1+2,4] !! 0
あたりのことを言われてるのかな?

Haskellにおいて、評価は印字などの動作によってしか引き起されない。
だから、とりあえず単純な印字の例を挙げただけ。

べつに
print $ replicate ([3,1+2,4]!!0) "foo"
のような例でもかまわない。
(当然この場合も1+2は評価されない。)

Haskellでは、IOに関連づけられなければ、式が評価されることはない。
対話的環境でも暗黙のprintがなされていると考えられると思う。
(ちなみに、対話的環境では返り値がIOならばそれの実行を、
それ以外だったらprintをするようになっているのだと思う。)

当然、print $ [3,1+2,4]!!0で、
1+2が印字されないことをもって、評価されないと言っているわけではない。
print $ [3,error "foo", 4] !! 0
で、エラーが生じないというのと同じことを言ったつもりである。

もしかしたら、もっと根本的な誤りを突いているのかもしれない。
そうだったらもう少し詳しい説明をよろしくおねがいします。

276:デフォルトの名無しさん
04/10/17 17:56:48
>>273
を読んで分かった…
君はlazy evaluationがそもそも分かってないんだorz

lazy evaluationが、「必要」に応じて評価されるのは、
> > なにかすごく賢い"評価器とは切り離された装置"
> が必要性を判断してくれると仮定しなければ、
こういうのがなにかが必要性を判断するわけじゃないよ。
単にoutermost leftmost reductionをしてるだけ。

質問に答えて欲しい。
(0) [3, 1+2, 4] !! 0 と length [0..] > 0 の評価はそれぞれどう進む?
(1) seqの初心者が陥りやすい誤解について説明せよ
(2) Stateモナドは自分で書ける? (Yes/No)
(3) その評価の順序が分かる? (Yes/No)
(4) (Lazy)Stateモナドで無限loopが書けないのはわかってる? (Yes/No)

> IOというものは[](リスト)と同様にそこにある何かであり、
リストモナドも自分で定義できるし…

277:デフォルトの名無しさん
04/10/17 18:17:15
>>275
> 対話的環境でも暗黙のprintがなされていると考えられると思う。
それってLispでいうrea-eval-print loopなんじゃないの?


278:haskell初心者
04/10/19 17:22:32
先月から勉強しているのですが、
haskellでn個の中から、m個を取り出す組み合わせの数、mCnのプログラムの書き方がわかりません。
だれか教えてください。お願いします。

279:デフォルトの名無しさん
04/10/19 17:31:30
宿題ですか?

せめて自分でどこまでやったか書け。


280:haskell初心者
04/10/19 17:36:04
課題です、すいません。
漸化式で作るところまでは考えたのですが、C++と違ってfor文が使えないので、
自分ではどうしたらよいかわからなくなってしまいました。

281:デフォルトの名無しさん
04/10/19 18:01:50
解1: マジメに計算する。階乗はどう書く? mPn はどう書く? 両方が出来
たら適切な引数を与えて割ればいいよね。

解2: mCn = .. + .. といった形で書ける。 .. と .. はどちらもコンビネー
ションだけど、 m と n の部分が少し小さい。で、m や n が 0 とか 1
だったらどうなるか、というのを考える。そしたら再帰で書けるよな。

という2つの考え方があるよ。

282:haskell初心者
04/10/19 18:06:43
なるほど!
ありがとうございました。

283:デフォルトの名無しさん
04/10/19 18:42:26
ここは優しいインターネッツですね

284:デフォルトの名無しさん
04/10/19 20:27:15
haskellの課題が出る講義があることに驚き。東大情報?
そのレベルの学生が再帰プログラムに不慣れなことにも驚き(失礼!)。


285:デフォルトの名無しさん
04/10/19 21:05:26
東大理情ではOcamlはやりますがHaskellはやりません。
工学部計数工学科(武市先生のいるとこ)ではHaskellをやる(人もいる)。

それにしても「関数型プログラムは理解し易くて初心者向き」なんじゃないのか...

286:デフォルトの名無しさん
04/10/19 21:39:10
東京工科大じゃないの?
URLリンク(www.teu.ac.jp)
と思ったけど課題内容が違うから違うのかな。

287:デフォルトの名無しさん
04/10/19 22:15:31
京都産業大学?

288:デフォルトの名無しさん
04/10/19 22:29:15
>>287
呼んだ?

289:デフォルトの名無しさん
04/10/20 02:30:38
漸化式が作れたのならプログラムのほとんどができたようなもんじゃないか

290:デフォルトの名無しさん
04/10/20 04:03:09
-- 数え上げobscured。c 10 3 などとして使う
c = flip ((length .) . filter . (. length . filter id) . (==)) . 
      (foldl ((=<<) . (. (return .) . (:)) . (>>=) ) [[]]) . (flip replicate [True, False]) 

291:デフォルトの名無しさん
04/10/20 18:34:44
ぐっ。↑を導いた過程の解説きぼんぬ。

292:デフォルトの名無しさん
04/10/20 18:53:01
コマンドプロンプトみたいなものを作ろうと思ってまず下のような単純なのを作って
hugsで動かしてみたら問題なく動いたのですが、ghcでコンパイルして実行すると、
プロンプト "$ " が表示されず、適当にキー入力したあと ":!" でループを抜けると、
入力した個数分のプロンプト "$ " がずらずらと表示されてしまいます。
ちなみに、ghciではhugsと同様に期待通りの動作です。
いったいどうすればghcでも期待通りの動作になるんでしょう?

main = do {
putStr "$ ";
str <- getLine;
case str of {
":!" -> return ();
_ -> main } }

ghcはver 6.2.2と6.2.1で試してみましたがどちらも同じ結果でした。

293:デフォルトの名無しさん
04/10/20 19:25:08
hFlush あたりを使うとよいのでは?

>>290 の導出過程希望。
まさか直接書いたの?

294:292
04/10/20 20:09:56
>293

putStrのあとに hFlush stdout を入れてやったらうまくいきました。

でも最初は実行順序が狂ってるのかと思ってしまいました。

295:デフォルトの名無しさん
04/10/20 22:40:10
>>294
ghcはターミナルではLineBufferingだから一行たまるまで出力されない。
hSetBuffering stdout NoBufferingを最初に書いてもいい。

>>291
>>293
手で地道にpoint-freeに書き換えました:-)
元は確か 
-- not tested
c n m = length $ filter ((m ==).length.filter id) $
            foldl (\ys xs -> [ x:y | x <- xs, y <- ys]) [[]]
                 $ replicate n [True,False]
こんな感じ。
自動化してフィルタプログラムにするとおもしろそう。

296:292
04/10/20 23:26:27
表示の問題は解決したんですが、他の部分に影響が出てしまいました。

プロンプトからの入力をParsecを使ってパースしようとしてるんですが、
文法の都合上Parsecのtryを使ってる部分があります。
hFlushとかstdoutは import IO しないといけないみたいなのでやってみると
そのtryを使っているところで

ERROR ".\test.hs":15 - Ambiguous variable occurrence "try"
*** Could refer to: System.IO.Error.try Text.ParserCombinators.Parsec.Prim.try

とかいうエラーが出てしまいます。(処理系はhugsです。ghcでも似たようなエラー)
どうしたら良いんでしょう?

一応パーサの部分とstdoutが必要な部分は完全に切り離されているので
パーサ部分を別のモジュールにしてやることで回避出来ることは確かめましたけど、
それ以外の方法はあるのでしょうか?

297:デフォルトの名無しさん
04/10/20 23:55:30
>>296
import qualified Text.ParserCombinators.Parsec as Parsec
して
Parsec.try と書くとか
import System.IO.Error ( hFlush, stdout, ... -- tryを以外だけリスト)
とか

For futher details, see section 5.3 of the Haskell 98 report.

298:292
04/10/21 00:45:52
>>297

ありがとうございます。
後者のやり方を使ってみます。

299:デフォルトの名無しさん
04/10/21 08:35:37
>>295
おおう、そのcならまともに読めますね。
((=<<) . (. (return .) . (:)) . (>>=)) の部分はやはりlist comprehensionからの変形か。
[[Bool]]が渡っているところをfuseして、さらに読解不能なコードにできるかもw


ところで、monadの話はどうなった。

300:デフォルトの名無しさん
04/10/24 15:41:02
なぜ、関数型言語は、Hello Worldを隠したがりますか?


301:デフォルトの名無しさん
04/10/24 15:43:54
   ∩___∩         |
   | ノ\     ヽ        |
  /  ●゛  ● |        |
  | ∪  ( _●_) ミ       j
 彡、   |∪|   |       >>300
/     ∩ノ ⊃  ヽ  
(  \ / _ノ |  |
.\ “  /__|  |
  \ /___ /

302:デフォルトの名無しさん
04/10/24 17:18:58
Haskellはじめたばかりなのですが、よくわからないので教えてください。
a = "b"
b = 1
c = do
 "c"
d = do
 2
と書いて、dだけ、
*** Binding : d
*** Outstanding context : (Monad b, Num (b c))
と言われるのはなぜですか?


303:デフォルトの名無しさん
04/10/24 20:58:48
文字列は文字のリストで、リストはMonadクラスのインスタンスだから。
数値はMonadクラスのインスタンスではないから。

304:デフォルトの名無しさん
04/10/24 23:11:39
>>303
ありがとうございます。
doの中からは、Monadクラスのインスタンスを返すことは出来るけど、
他のものは返せないと。
doの中から数値を返したい場合はどうしたらよいのでしょうか?
Monadクラスのインスタンス作って返すしかないってことでしょうから、
returnを使って、IOモナドを返せばいいということなのでしょうか?
IOモナドって使わなくてすむなら使わないほうがいいみたいなのですが、
数値を返す関数はdo使わなくてもかけるだろうってことなのかな?
Haskellは難しいです。頭がクラクラします。


305:デフォルトの名無しさん
04/10/25 00:15:45
>>304
> doの中から数値を返したい場合はどうしたらよいのでしょうか?
一般には無理。リスト等、中身を取り出せるモナドもある。
f :: Int
f = head $ do return 3

> 数値を返す関数はdo使わなくてもかけるだろうってことなのかな?
なんでモナドが使いたいのかわからない。
例えばどんな「数値を返す関数」にモナドを使おうと思うわけ?

306:デフォルトの名無しさん
04/10/25 01:22:05

       ∧_∧   / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
      ( ´ 曲`)  < モナドナ♪ドーナー♪ドーナー♪
      ⊂    )つ \_____________
       (_⌒ヽ
         )ノ `J



次ページ
最新レス表示
レスジャンプ
類似スレ一覧
スレッドの検索
話題のニュース
おまかせリスト
オプション
しおりを挟む
スレッドに書込
スレッドの一覧
暇つぶし2ch