第二回Haskell読書会開催
Scalaのzipが
なんか慣れない。
scala> Array(1,2,3) zip Array(4,5,6)
res1: Array[(Int, Int)] = Array((1,4), (2,5), (3,6))
Haskellだとこんな感じでしょ。
Prelude> [1,2,3] `zip` [4,5,6]
[(1,4),(2,5),(3,6)]
Pythonだと
[1,2,3].zip([4,5,6])
とはできない。
>>> zip([1,2,3],[4,5,6])
[(1, 4), (2, 5), (3, 6)]
HaskellのArrow
Arrowを学ぶ。Programming with Arrowsを読んでから、「Arrowのはなし」というニコニコ動画をみるのがわかりやすい。イメージは3番目が参考になる。
Arrowを使って奇数列を作ってみる。 0から始まる数列を&&&で分岐させて一方はそのまま戻して、もう一方はtailすることで1から始まる数列にして、合流したら足し合わせる。
Prelude Control.Arrow> let odds = (tail) &&& id >>> (uncurry (zipWith (+)))
Prelude Control.Arrow> take 10 $ odds [0,1..]
[1,3,5,7,9,11,13,15,17,19]
他、参考にしたサイト
RWHではArrowは15.4.2にちょっとだけ触れられている。
Real World Haskell―実戦で学ぶ関数型言語プログラミングBryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。
Haskellでcat
bindの使い方メモ
import System.Environment
cat:: String -> IO ()
cat = (>>= putStr) . readFile
main = do (file:_) <- getArgs; cat file
追記10.02.13
コメントよりheadを使えば一行で書ける。
main=getArgs>>=readFile.head>>=putStr
Hakellでテンポラリディレクトリやテンポラリファイル
テンポラリファイルをエディタでいじって、保存するとテンポラリファイルの内容を読んでHsSyckでパースして出力する
import System.IO
import System.Process
import System.Directory
import System.Environment
import Control.Monad (liftM)
import Data.Yaml.Syck
main :: IO ()
main = do
tmpdir <- getTemporaryDirectory
(pathOfTempFile, h) <- openTempFile tmpdir "temp.yaml"
editor <- liftM (lookup "EDITOR") getEnvironment
case editor of Just ed -> (>>= waitForProcess) . runCommand $ ed ++ " " ++ pathOfTempFile
Nothing -> error "command error\n"
hClose h
inpStr <- readFile pathOfTempFile
yamlstr <- parseYaml inpStr
print yamlstr
removeFile pathOfTempFile
return ()
HoogleとGHCの標準ライブラリドキュメントが手放せない身体になってきた。
Real World Haskell―実戦で学ぶ関数型言語プログラミングBryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。
もっとHaskellの本出ないかなぁ。Principles of Biomedical InformaticsのHaskell阪みたいなのとか。
HaskellでPitを使う
perlにもConfig::Pitあるし、Pythonにもあるしという状況なので、Haskellでネットワークのちょろっとしたものを書くときにもパスワードをハードコードしないで、pitのやつを使いたかった。
module HsPit (
pitGet,
pitSet
)
where
import System.FilePath ((</>))
import System.Directory
import Data.Yaml.Syck
pitGet :: String -> IO [(String,String)]
pitGet query = do
home <- getHomeDirectory
do yaml <- parseYamlFile (home </> ".pit" </> "default.yaml")
case n_elem yaml of
EMap list -> return $ map (\keyval -> (,) ((fromYaml . fst) keyval) ((fromYaml . snd) keyval)) $ concatMap (fromEMap . snd) $ filter checkElem list
where checkElem ynode = ((n_elem . fst) ynode) == (EStr (packBuf query))
otherwise -> return []
where
fromYaml MkNode {n_elem=EStr str} = unpackBuf str
fromEMap MkNode {n_elem=EMap nodes} = nodes
pitSet = error "Not implemented"
HsSyckの使い方はPugsのYamlコードを参考にした。
で、例えばtwitterでつぶやくときには
import Network.HTTP
import Network.URI
import Codec.Binary.Base64.String
import Data.Maybe
import HsPit
tweet username password msg = simpleHTTP req where
req = Request uri POST [ah] "" where
ah = Header HdrAuthorization $ "Basic " ++ encode (username ++ ":" ++ password)
uri = fromJust $ parseURI $ "http://twitter.com/statuses/update.xml?"
++ urlEncodeVars [("status", msg)]
main = do
userdata <- pitGet "twitter"
case lookup "username" userdata of Just username ->
case lookup "password" userdata of Just password ->
tweet username password "tWeet"
なんかごちゃごちゃとしてしまった。
HaskellでYAML
HaskellでYAMLを扱うライブラリはyaml,HsSyckがあるんだけどlibyamlのバインディングであるyamlのほうは使い方がわからん。
なので、HsSyckの使い方を覚えた。
import Data.Yaml.Syck
global_tag = mkNode $ EStr $ packBuf "Item 1"
name_tag = mkNode $ EStr $ packBuf "name"
name_value = mkNode $ EStr $ packBuf "kzfm"
email_tag = mkNode $ EStr $ packBuf "address"
email_value = mkNode $ EStr $ packBuf "xxx@gmail.com"
pass_tag = mkNode $ EStr $ packBuf "password"
pass_value = mkNode $ EStr $ packBuf "snail"
item = mkNode $ EMap [(name_tag,name_value),(email_tag,email_value),(pass_tag,pass_value)]
node = mkNode $ EMap [(global_tag,item)]
main = do
emitYamlFile "test.yaml" node
作成されたtest.yamlの中身
---
? "Item 1"
:
? "name"
: >-
kzfm
? "address"
: >-
xxx@gmail.com
? "password"
: >-
snail
これをperlでparseしてみる
use YAML;
my $filename = "test.yaml";
my $doc = YAML::LoadFile($filename);
print YAML::Dump($doc);
実行結果
---
Item 1:
address: xxx@gmail.com
name: kzfm
password: snail
ナイス!
hoogleをローカルで
昨晩、String -> ByteStringに変換する関数がわかんね的なことをtweetしたらHoogeleで型検索出来ることを教えてもらった。
Hoogle 激ヤバ!マスト!!!!(ローカルに)
というわけで、ローカルで検索できるように
sudo cabal install hoogle
これだけ。
~/.cabal/binにhoogleっていうコマンドがインストールされるのでパス通しておく。
$ hoogle "String -> ByteString"
Data.ByteString.Char8 pack :: String -> ByteString
Data.ByteString.Lazy.Char8 pack :: [Char] -> ByteString
Prelude read :: Read a => String -> a
Text.Read read :: Read a => String -> a
Data.String fromString :: IsString a => String -> a
...
これはアンセムといっても間違いない。
Haskellのプログラムの中でエディタを使ってファイルをいじる
週末はニューラルネットの実装でもするつもりでいたのに、突然
Haskellのプログラムの中でファイルをエディットして保存したら、そのファイルの中身を読む
ということをやりたくなってしまった。要するにHaskellでこれがやりたくなった。
import System.FilePath ((</>))
import System.Directory
import System.Process
import System.Environment
import Control.Monad (liftM)
main = do
home <- getHomeDirectory
(file:_) <- getArgs
editor <- liftM (lookup "EDITOR") getEnvironment
case editor of Just ed -> (>>= waitForProcess) . runCommand $ ed ++ " " ++ (home </> file)
Nothing -> error "command error\n"
inpStr <- readFile $ home </> file
print inpStr
最初、
runCommand $ ed ++ " " ++ (home </> file)
って書いてて、あーブロックされてないんだろうなぁと。探したらどう書く?にあった。
あと、RWHのモナド変換子の章を読むべし的な流れになってる。
Real World Haskell―実戦で学ぶ関数型言語プログラミングBryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。
アッカーマン関数をHaskellで
計算論を読んでたらアッカーマン関数が出てたのでHaskellで書いてみた。
ack 0 n = n + 1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) $ ack m (n-1)
定義をそのまま書き下せばいい。
*Main> ack 1 2
4
*Main> ack 3 2
29
*Main> ack 3 4
125
それにしても計算論難しい。
プログラミングHaskell


Principles of Biomedical Informatics
計算論 計算可能性とラムダ計算 (コンピュータサイエンス大学講座)