関数型プログラミング言語Haskell Part26
レス数が950を超えています。1000を超えると書き込みができなくなります。
0001デフォルトの名無しさん
2014/07/27(日) 13:46:32.03ID:deqguEnhhaskell.org (公式サイト)
http://www.haskell.org/
前スレ
関数型プログラミング言語Haskell Part25
http://peace.2ch.net/test/read.cgi/tech/1393313450/
0931デフォルトの名無しさん
2015/01/05(月) 13:29:35.01ID:r5Vta5Zshttps://gist.github.com/yantonov/10083524
0932デフォルトの名無しさん
2015/01/05(月) 13:31:02.02ID:PY+NF+zg普通は副作用とヌルがあるから IO (Maybe String)
でも普通の常識を疑うためにHaskellやってるんだろ?
0933デフォルトの名無しさん
2015/01/05(月) 13:38:45.45ID:rVk7ZNEdその方法が一番いい。
1. 素直な方法なので実装しやすくバグが入りにくい。
2. 空リストを考慮しなくてもよく場合分けが必要ない。
3. プログラムソースが見やすく何を求めているのかがよく分かる。
4. 奇数番目だけでなく、x 行おきの場合にも対応でき応用が利く。
0934デフォルトの名無しさん
2015/01/05(月) 13:54:22.37ID:UJnBa08Nリスト走査を1度ですませたいなら融合変換すればよいのでは.
0935デフォルトの名無しさん
2015/01/05(月) 13:57:36.10ID:56v1L+Z7いやあ,ちょっとした使い捨て的な処理なので,そんなに真面目に例外処理を考えてなかったです
>>933
ひどく効率が悪いとか,そういうことはないんですね
じゃあ初心者としてはわかりやすさ優先でいっときます
なんかこう
s <- getContents
putStr $ unlines $ map fst $ filter (odd . snd) $ zip (lines s) [0..]
みたいな感じで
0936デフォルトの名無しさん
2015/01/05(月) 14:03:41.15ID:56v1L+Z7融合変換って初めて聞きました
ちょっと勉強してみます
0937デフォルトの名無しさん
2015/01/05(月) 14:25:19.60ID:rVk7ZNEd>>929 の方法でも走査は一度きりなんだが・・・
0938デフォルトの名無しさん
2015/01/05(月) 15:00:51.08ID:1xEaC2gz一度も具体的な話が出てこないから、Botだと思いますよ。
0939デフォルトの名無しさん
2015/01/05(月) 15:18:52.82ID:r5Vta5Zs0940デフォルトの名無しさん
2015/01/05(月) 15:18:54.70ID:v9pP0JGy0941デフォルトの名無しさん
2015/01/05(月) 15:51:07.05ID:OMSF4NShこれは同感
エディタとかで最初から最高の環境目指すと考えすぎで止まってしまう
0942デフォルトの名無しさん
2015/01/05(月) 15:59:36.20ID:UJnBa08Nzipで一回,filterで一回,計2回ではないでしょうか?
0943デフォルトの名無しさん
2015/01/05(月) 16:26:46.03ID:rVk7ZNEdあぁ走査って、リストの要素数 n に対して、
zip の計算量 n、filter の計算量 n とすると、
全体で 2n の計算量になる、と言う意味なのか。
勘違いしてた。
でもそれだと今度は、融合変換しても走査数は変わらないのでは?
融合変換って、中間データ構造(今の問題ならタプル)を消すことでしょ。
0944デフォルトの名無しさん
2015/01/05(月) 16:29:22.31ID:UJnBa08N中間リストがなくなればその分の走査が減るとおもいます.
0945デフォルトの名無しさん
2015/01/05(月) 17:05:16.52ID:4q+Qt2eNアドバイスありがとうございました
0946デフォルトの名無しさん
2015/01/05(月) 17:43:05.75ID:rVk7ZNEd中間リストって、filter が作る中間リスト?
zip が作る [(String, Int)] に対して「ひとつおきに取り出す処理」は、
あなたの言う走査には含まれない?
融合変換で中間リストが消えて走査数が減ると言うのなら、元々の操作数は、
1. zip が引数のリストを分解する
2. zip がリストを作る
3. filter がリストを分解する
4. filter がリストを作る
の 4 つで、そのうち 2 と 3 が消えて 2つになるのでは?
あるいは、zip は「2つのリスト」に対して処理するから、
元々の走査数は zip 2、filter 1 で計 3 つになるとか?
走査数の意味がイマイチ分からなくなった。
何を以て走査数と言ってる?
0947デフォルトの名無しさん
2015/01/05(月) 18:31:50.63ID:UJnBa08NoddElems :: [a] -> [a]
oddElems = filter' snd (odd . fst) . zip [0..]
filter' _ _ [] = []
filter' f p (x:xs) = if p x then f x : filter' f p xs
このとき,oddElem の入力となるリストを es.その長さを n = length es とします.
zip [0..] は関数で,この関数が結果のリスト全体を作成するには es の全要素を辿ります.
zip [0..] es が生成するリストを es' とすると,そのは長さは es の長さと同じ n です.
filter' snd (odd . fst) es' は結果のリスト全体を生成するのに es の全要素を辿ります.
融合変換して es' という中間リストがなくなれば,辿るべきリストが1つ減っていることが期待できますよね.
0948デフォルトの名無しさん
2015/01/05(月) 18:48:33.68ID:UJnBa08Nfilter' snd (odd . fst) es' は結果のリスト全体を生成するのに es' の全要素を辿ります.
0949デフォルトの名無しさん
2015/01/05(月) 18:49:41.11ID:UJnBa08N0950デフォルトの名無しさん
2015/01/05(月) 19:20:48.83ID:rVk7ZNEdそもそも遅延評価だから、zip に 1回、filter に 1 回というたどり方はしなくて、
走査の定義をハッキリさせておかないと非常にややこしくなるんだが・・・
リストに対する融合で消えるのはあくまで、
「リストの作成」とその直後の「リストの分解」という一対の処理だけだよ。
zip が行う「タプルを作る処理」や filter が行う「奇数番目かどうか判定する処理」は消えない。
この 2 つの処理が全体で何回行われるかというと、融合されようが、されまいが、
きっちり最初に zip に渡されたリストの要素数分だ。
減りも増えもしない。
(正確には、結果のリストをどう評価するかによるが)
融合によってリストの作成分解処理が一対消えるから、
この処理のことを走査と言うのなら確かに走査数は減ることになる。
タプルの作成や奇数判定も走査の中に含めるのなら、走査数は変わらんよ。
で、俺は走査と言えば、たとえば GCC は C 言語の構文解析を一度スキャン(走査)で行える、
とかいう時のスキャンのイメージがあるから、それなら zip と filter の組み合わせは
リストに対して一度のスキャンで行える、と言ったんだ。
遅延評価だから二度もスキャンする必要はないからね。
0951デフォルトの名無しさん
2015/01/05(月) 19:47:30.17ID:UJnBa08N中間リストの生成を除去するといえばよかったですね.
0952デフォルトの名無しさん
2015/01/05(月) 20:19:28.54ID:UJnBa08NoddElems = filter' snd (odd . fst) . zip [0..]
filter' snd (odd . fst) . zip [0..]
⇔ { zipp = uncurry zip とする }
filter' snd (odd . fst) . zipp . (,) [0..]
⇔ { addifodd (i,x) xs = if odd i then x:xs eles xs とする }
foldr addifodd [] . zipp . (,) [0..]
⇔ { phipair (xxs,yys) = if null xxs || null yys then Nothing else Just ((head xxs,head yys),(tail xxs, tail yys)) とする }
foldr addifodd [] . unfoldr phipair . (,) [0..]
⇔ { hylo f e phi x = case phi x of {Nothing -> e; Just (y,z) -> f y (hylo f e phi z)} とする }
hylo addifodd [] phipair . (,) [0..]
まちがえてなければ,これで融合変換できたことになると思います.
oddelems = hylo addifodd [] phipair . (,) [0..]
0953デフォルトの名無しさん
2015/01/05(月) 21:13:52.44ID:KI3U0yKn0954デフォルトの名無しさん
2015/01/05(月) 21:34:27.09ID:rVk7ZNEd内容は調べていないから融合できているかは知らんが、
何のために融合しようとしているの?
本末転倒になってはいないか?
適当なテストプログラムを書いてコンパイルし、
RTS オプション の -s を付けて実行して処理時間を測ってみ。
素直に filter と zip を使った方が速いから。
と言っても、かなり大きなリストで試さないと差は見えてこないから、
>>929 の使い方なら実用上どちらを使っても変わらんが。
0955デフォルトの名無しさん
2015/01/05(月) 21:49:58.07ID:rVk7ZNEdちなみに、それよりも >>947 の方法の方が速い。
また、ヒープ領域の使用量も速さと同じ結果。
素直に実装した方が少ない使用量で済む。
0956デフォルトの名無しさん
2015/01/05(月) 22:23:19.50ID:JId0mbKZ0957デフォルトの名無しさん
2015/01/05(月) 23:47:34.38ID:mLtk6pyNマジすか?
0958デフォルトの名無しさん
2015/01/06(火) 00:02:57.77ID:WjhpL2zQそもそも,計算量オーダーが同じならコードがわかりにくくなった分,劣化してる可能性大ですねぇ.
0959デフォルトの名無しさん
2015/01/06(火) 00:35:30.77ID:WjhpL2zQの処理と unlines . oddelems . lines の部分を融合変換したもの
interact (show . length . hylo addifodd "" numlines)
の処理とを比較してみました.63469440行ある単語データファイル(600MB)を食わせてみたところ
手元の計算機でかかった時間は以下の結果
前者はTotal time 33.59s ( 34.20s elapsed) %GC time 14.6% (24.5% elapsed)
後者はTotal time 27.87s ( 28.38s elapsed) %GC time 7.5% (19.7% elapsed)
IO部分の時間を図ってないのでなんともいえないですが,この場合は差がでるようにみえますね.
コンパイルオプション-O2
0960デフォルトの名無しさん
2015/01/06(火) 00:37:44.25ID:WjhpL2zQ0961デフォルトの名無しさん
2015/01/06(火) 00:45:53.98ID:WjhpL2zQ2つめの処理は
interact (show . length . hylo addifodd "" numlines . (,) [0..])
のまちがい.
numlines (_,[]) = Nothing
numlines (i:is,xs) = case break ('\n'==) xs of {
(ys,_:zs) -> Just ((i,ys),(is,zs));
(ys,[]) -> Just ((i,ys),(is,[]))}
0962デフォルトの名無しさん
2015/01/06(火) 07:12:15.34ID:1NZMwfJDそれはなによりです
[0..]とzipしてfilterする方法では回りくどくないかなと心配してた>>929もさぞ喜んでいることでしょう
0963デフォルトの名無しさん
2015/01/06(火) 09:21:05.66ID:Ap0lJ8Jthaskellでタダシの心と身体を守るんだぞ
0964デフォルトの名無しさん
2015/01/06(火) 09:58:56.58ID:iarVVv2tトイコードで書けるような小さいものを相手にしてる場合はいいけど,
データ量が多くなるとすぐにダメになって,参照型とかモナドのオンパレードにしないといけないのかと思ってた.
0965デフォルトの名無しさん
2015/01/06(火) 10:00:05.28ID:iarVVv2t0966デフォルトの名無しさん
2015/01/06(火) 10:29:48.03ID:+nyULczy0967デフォルトの名無しさん
2015/01/06(火) 12:42:53.16ID:4YMDVwAoRulesプラグマで融合変換して中間リストを除去してるから
自分で再帰を書いたらその部分がボトルネックになる
0968デフォルトの名無しさん
2015/01/06(火) 14:31:17.60ID:gN1CYWxIまあ融合変換は現実的には自分の手でやるもんじゃないよね。
ところで>>959の差ってどこで生まれてるんだろ?
zip して filter は素のリストだと融合変換してくれないの?
unlines のところの中間リストの違い?
http://hackage.haskell.org/package/stream-fusion-0.1.1/docs/Data-List-Stream.html
とかを使うと変わるかな?
0969デフォルトの名無しさん
2015/01/06(火) 17:57:28.03ID:1NZMwfJDfilter が優良生産者として実装されているから、
同じく優良生産者として機能しているときの zip に続けても融合されない、
ということでは?
http://www.kotha.net/ghcguide_ja/latest/rewrite-rules.html#idm140193846702112
0970デフォルトの名無しさん
2015/01/06(火) 19:30:02.76ID:gN1CYWxIああ、他の Data.List 関数と一緒に使うならそうか。
>>969
ソース読めって書いてあるとおり読んでみると、
build を使ってれば優良生産者で foldr を使っていると優良消費者で、
両者になるのは同時に可能ってことだと思うんだけど。
0971デフォルトの名無しさん
2015/01/06(火) 20:06:42.53ID:NJ/kfRzjテストデータの生成に使ったコード: http://codepad.org/2Qljhutm
(1) >>959のコード1つ目 : http://codepad.org/Guy2CswB
(2) >>959のコード2つ目 : http://codepad.org/S3DdUiGL
(3) 素直にData.Listの関数だけで書く : http://codepad.org/7SZtvyJ9
実行結果
(1) Total time 25.02s (25.65s elapsed) %GC time 19.9% (19.8% elapsed)
(2) Total time 23.05s (23.62s elapsed) %GC time 22.0% (21.8% elapsed)
(3) Total time 24.45s (25.06s elapsed) %GC time 20.3% (20.4% elapsed)
>>967で書いた通り、自分で書いた再帰をData.Listの関数と一緒に使うと遅くなる
ほとんど差は無いので手で融合変換する手間を考えたら素直にData.Listの関数だけで書いた方がマシ
以下はおまけ
(4) Text + ByteString : http://codepad.org/WcNZH4zD
(5) Text + ByteString + Vector : http://codepad.org/5lAwD8PI
実行結果
(4) Total time 13.61s (14.18s elapsed) %GC time 2.9% (3.4% elapsed)
(5) Total time 2.21s ( 2.68s elapsed) %GC time 2.2% (2.2% elapsed)
0972デフォルトの名無しさん
2015/01/06(火) 20:43:09.13ID:gN1CYWxI融合変換はちゃんとされてると。
でも差は意外と無かった?
0973デフォルトの名無しさん
2015/01/06(火) 21:27:05.66ID:1NZMwfJDごめん、自分でリンク貼っておいて見落としてた。
filterは優良生産者であると同時に優良消費者でもあった。
0974デフォルトの名無しさん
2015/01/06(火) 21:35:49.65ID:1NZMwfJD融合変換と言っても、トイプログラムや日常のちょとしたスクリプト程度ではあまり意味ないかもね。
Repaみたいな、ああいったもので本当に活きてくる、というかなくてはならない存在だと思う。
0975デフォルトの名無しさん
2015/01/06(火) 21:52:22.72ID:0YpM91P00976デフォルトの名無しさん
2015/01/06(火) 22:06:08.57ID:WLnq9lHu0977デフォルトの名無しさん
2015/01/06(火) 22:08:58.99ID:1NZMwfJD全く役にはたたんが、こういう発想ステキ
0978デフォルトの名無しさん
2015/01/07(水) 07:46:09.67ID:gDzpAQ9k"bfget"の型がどうなっているのかわからなくなってしまいました。
お知恵をお借りしたく... (ghc version 7.6.3, lens-4.3.3)
--------------------
{-# LANGUAGE TemplateHaskell #-}
module A where
import Control.Lens (ALens',makeLenses,cloneLens,lens,to,(.~),(%~),(&),(^.))
import Data.Word (Word32,Word64)
import Data.Bits (Bits,FiniteBits,complement,shiftL,shiftR,rotateL,(.|.),(.&.))
import Test.HUnit (Test,test,runTestTT,(~=?))
data Regs = Regs { _r0 :: Word32, _r1 :: Word64 } deriving (Show, Eq)
$(makeLenses ''Regs)
(.#.) :: (Functor f, FiniteBits a, Bounded a, Integral a) =>
ALens' Regs a -> (Int, Int) -> ((a -> f a) -> Regs -> f Regs)
(.#.) r (lsb, nbits) = let
-- ??? bfget :: Integral a => Regs -> a
bfget rs = rs ^. (cloneLens r) . to (flip shiftR lsb . (.&. complement mask))
bfset :: Integral a => Regs -> a -> Regs
bfset rs x = rs & (cloneLens r) %~ \ w -> (mask .&. w) .|. (complement mask .&. shiftL (fromIntegral x) lsb)
mask :: (Bits a, Bounded a) => a
mask = flip rotateL lsb $ shiftL maxBound nbits
in lens bfget bfset
0979デフォルトの名無しさん
2015/01/07(水) 07:46:43.21ID:gDzpAQ9kmain = runTestTT $ test [
(rs & r0 .#. (4,16) .~ 0xcafe) ^. r0 .#. (4,16) ~=? 0xcafe
, (rs & r0 .#. (8,24) .~ (rs ^. r0 .#. (8,24))) ~=? rs
, ((rs & r0 .#. (0,32) .~ 0xabadcafe) & r0 .#. (0,32) .~ 0xdeadbeaf) ~=? rs {_r0=0xdeadbeaf}
, (rs & r1 .#. (4,16) .~ 0xcafe) ^. r1 .#. (4,16) ~=? 0xcafe
, (rs & r1 .#. (8,24) .~ (rs ^. r1 .#. (8,24))) ~=? rs
, ((rs & r1 .#. (0,64) .~ 0xabadcafe) & r1 .#. (0,64) .~ 0xdeadbeaf) ~=? rs {_r1=0xdeadbeaf}
]
where rs = Regs {_r0 = 0x01234567,_r1=0x0123456789abcdef}
0980デフォルトの名無しさん
2015/01/07(水) 10:16:03.90ID:gDzpAQ9khttp://lpaste.net/117957
0981デフォルトの名無しさん
2015/01/07(水) 18:26:38.49ID:ia1dpi4pperlのラクダ、pythonの蛇のようにマスコット?
レス数が950を超えています。1000を超えると書き込みができなくなります。