1. Top » 
  2. Haskell

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  • Genre:

【Haskell】関数の定義とパターンマッチについて語る(一度目)

Haskellというのはいわゆる関数型言語と呼ばれるモノで、ひたすら関数が大事。
まぁ自分も詳しく分かっている訳ではないけれども

関数を中心に考えて関数を大事にする言語=関数型言語


という認識でとりあえずは大丈夫だと思う。
またHaskellには代入がない。
ついでに言えばfor文もwhile文もswitch文もない。
変数はちゃんと使えるのだけれども、代入するという概念がない。
一般的な手続き型言語のCなどでは代入文を

int x = 10


のように書くのだけれども、代入がないため、このような文は出てこない。
よってHaskellで=が出てきたらそれは関数であることがほとんどということになる。


それではパターンマッチと関数宣言の話をする。
ある関数 function の定義は次のように書く。

function :: 第一引数の型 -> 第二引数の型 -> ・・・ -> 第n引数の型 -> 返り値の型
function args1 args2 ・・・ argsn = 本体


ただ例示は理解への試金石、あまり一般的な話でも分からないので具体的な例を書く。
まずはじめに、ある値の絶対値を返す関数getAbsとする。

test = -10
main = print $ getAbs test
getAbs :: Int -> Int
getAbs n = if n < 0 then -n
else n

いわゆる普通の書き方であり、10が出力される。

さて、ここからHaskell話に入る。
今、式としてgetAbs n = ...というような関数定義をしている。
今引数を1つだけなので、この場合、引数一つ分という意味でnと書いてある。
その引数として与えられた値をnとして利用できる。

このように値のパターンによる場合分けのことをパターンマッチと呼ぶ。
これだけでは意味がまだ分からないので次の例を見る。自分で割り算を作ろう。
ちなみにHaskellで割り算をするとき、x / y は div x y と書く。

mdiv :: Int -> Int -> Int
mdiv x y = div x y

このように通常のdivをただ置き換えただけの関数では、たとえばyに0が入るとエラーが起きる。
(ゼロ割ができないため)
ここでこれを省くには次のようにする方法がまず考えられる。

mdiv :: Int -> Int -> Int
mdiv x y = if y /= 0 then div x y else x

通常の考え方でif文を使って0割を省く。
この書き方で問題ないのだけれども、パターンマッチを使うと次のように書ける。

mdiv :: Int -> Int -> Int
mdiv x 0 = x
mdiv x y = div x y

パターンマッチは上から順番にチェックされ、この書き方の時

引数が ある値xと0で渡ってくる場合 → 0 を返す
引数が ある値xとyで渡ってくる場合 → div x yを返す


と書いていることになる。

今、xと書いたとき、引数をxに束縛して利用するため、これを変数パターンと呼ぶことがある。
今、0と書くと、引数として0が渡された場合にマッチする。これをリテラルパターンと呼ぶことがある。
(たぶんリテラルパターンと呼んでもいい。)
また数値0のようなものだけではなく、文字列""や文字''もリテラルパターンとして利用できる。

あれ、結局パターンマッチというのはif文とかswitch文の代わりに入っているようなものなのだろうか。
また次回、語ります。
また、次回は他のパターンも使ってプログラムを書いてみます。


category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法
【Haskell】C言語の構造体のようなものをHaskellで利用する
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.0)
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.1)
【Haskell】コマンドライン引数の取得を活用する。
【Haskell】絶対パスからファイル名だけを取り出す
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.2)
【Haskell】ディレクトリ内を表示するlsをHaskellで書く
スポンサーサイト

【Haskell】ディレクトリ内を表示するlsをHaskellで書く

いわゆるlsコマンドまたはdirコマンドの簡単な部分だけを実装します。
ただし別の用途に使うことを前提としている話なので

 カレントディレクトリ .
 ペアレントディレクトリ ..

の二つについては表示から省くためにfilterをかけます。

import Directory

main = ( getDirectoryContents "." ) >>= printList

printList :: [String] -> IO()
printList ls = pList $ filter notCDPD ls
where
pList :: [String] -> IO ()
pList (x:xs) = do c <- getCurrentDirectory
putStrLn ( c ++ x )
pList xs
pList [] = putStr ""

notCDPD :: String -> Bool
notCDPD "." = False
notCDPD ".." = False
notCDPD other = True


bash-3.2$ ghc -o listing listing.hs
bash-3.2$ ./listing.exe
d:\taki\program\haskell\directorylisting.exe
d:\taki\program\haskell\directorylisting.hi
d:\taki\program\haskell\directorylisting.hs
d:\taki\program\haskell\directorylisting.o


このように。

基本的にはDirectoryに用意されている関数を使っているだけです。

getCurrentDirectory :: IO FilePath
 カレントディレクトリのパスを返す

getDirectoryContents :: FilePath -> IO [FilePath]
 現在のディレクトリ内のコンテンツをリストで返す。

FilePathというのはPreludeの中で書かれていて、Stringのことです。



category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法
【Haskell】C言語の構造体のようなものをHaskellで利用する
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.0)
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.1)
【Haskell】コマンドライン引数の取得を活用する。
【Haskell】絶対パスからファイル名だけを取り出す
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.2)

【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.2)

とりあえず元々の機能を確認します。

ver.0
 標準入力からリストを受け取り、HTMLへと生成する
ver.1
 src.txtというファイルからリストを受け取り、htmlsrc.txtというファイルへ出力する

また新しく次のようなことが出来るようになりました。


  • ドラッグしてきた1つのファイルのパスを取得できる
  • ドラッグしてきた複数のファイルのパスを取得して標準出力へ出力できる
  • 絶対パスからファイル名に相当する場所を拡張子付きで取り出す


以上のことからVer.2として次のようなものを目指します。
ver.2
 ドラッグしてきたテキストファイルからリストを読み込み、HTMLへと整形する。
 出力先はhtml_(入力ファイル名.txt).txtという形にする

こんな感じです。
どうせなら複数ファイル同時読み込み同時出力を目指してもいいですが
とりあえず簡単なところで1ファイル限定と行きます。
さて、過去数回を参考にすると、main関数は次のように書くことが出来ます

※補足 次の関数はそれぞれ次のような関数でした。

getHtml
 一行ずつHTMLへ整形する関数
yenToSpace、split、reverse、head
 円マークをスペースに変える、スペースで絶対パスを分割する、処理をしてファイル名を取り出す

import IO
import System

header = "<hr size=\"1\">category of Haskell:"
hreftp = "http://parabola0.blog86.fc2.com/blog-entry-"
optemp = "html_"

main = do args <- getArgs
let ddfilepath = head args
ddfilename = head . reverse . words $ split ddfilepath
output = optemp ++ ddfilename ++ ".txt"
infile <- readFile ddfilepath
putStrLn infile
outhandle <- openFile output AppendMode
hPutStrLn outhandle header
hPutStr outhandle $ unlines $ map getHtml $ lines infile
hClose outhandle


今まで作成した関数をうまく使っています。
また記述が長くなりそうな部分はletを使ってローカル変数を宣言します。

ddfilepath
 D&Dしてきたファイルの絶対パス
ddfilename
 D&Dしてきたファイルのファイル名
output
 D&Dしてきたファイルの名前から作った出力先ファイル名

さて、これで準備完了です。
コンパイルしてsrc.txtを適当に用意します。

例 src_haskell.txt
  src_java.txt


srcには一行が 記事番号+タブ+タイトル で構成された情報が入っているのでした。
ここではそれぞれJavaとHaskellの記事についてリストを作ってみました。

これを出来たばかりの実行ファイルへD&Dすると

出力 html_src_haskel.txt.txt
   html_src_java.txt.txt


といったようなファイルが実行ファイルと同じディレクトリに作成されました。
作成されたHTMLソースを貼り付けて終了です。


※補足
二重拡張子、あまりかっこよくないですね。
簡単にとれるのですけど・・・

簡単に言うと、パターンマッチにピリオドも追加してスペースに変化させます。
するとファイル名の部分は一番後ろの一つ前になるので、そのリスト path を

path = ["d:", "taki", "program", "haskell", "blog", "src", "txt"]
head .tail . reverse path


のようにすればいい。(分かってるなら実装しなさい)


次回からはまた別のことをするか、それともまだ何かちょこまかするか。
おそらくどちらかです。




category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法
【Haskell】C言語の構造体のようなものをHaskellで利用する
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.0)
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.1)
【Haskell】コマンドライン引数の取得を活用する。
【Haskell】絶対パスからファイル名だけを取り出す

【Haskell】絶対パスからファイル名だけを取り出す

ファイル名のリストを取り出せることは前回のことで分かった。
つまり入力ファイル名は、指定することなしにファイルを開くことに応用できる。
残りは、たとえば入力ファイル名がsrc_haskell.txtであれば
出力としてoutput_src_haskell.txt.txtのように、それに対応する結果を出力ファイルに書き出したい。
(うまくやれば拡張子を一つに出来るが、別に気にしなくてもいいかもしれない)

たとえばパス名というのは

d:\taki\program\haskell\src.txt


のような形で取得できる。ここからファイル名src.txtを得るにはどうすればいいか。
とりあえず次のようなやり方を考えた。


  1. ¥マークをスペースに変える
  2. 文字列をスペースで分けてリスト[String]として返す関数wordを通す
  3. リストとして [ ... "haskell", "src.txt"] のようなものを得る
  4. リストをひっくり返すreverseを通す ["src.txt", "haskell", ...]
  5. そのリストの先頭をheadで引っ張ってくる


つまり次のようにすればいい。
データはテスト。

test = "d:\\taki\\program\\haskell\\blog\\src.txt"
main = putStrLn $ head . reverse . words $ split test

split :: String -> String
split str = map yenToSpace test

yenToSpace :: Char -> Char
yenToSpace '\\' = ' '
yenToSpace x = x

これを動かすと次のように出力される。

d:\taki\program\haskell\blog\memo>ghc -o test test.hs

d:\taki\program\haskell\blog\memo>test.exe
src.txt


望み通りファイル名だけを取ってくることができた。





category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法
【Haskell】C言語の構造体のようなものをHaskellで利用する
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.0)
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.1)
【Haskell】コマンドライン引数の取得を活用する。

【Haskell】コマンドライン引数の取得を活用する。

しばらく取り組んでいるブログに役立つプログラム作りのために、少し脇道にそれて頑張る。
普通にコマンドライン引数を取得して出力するだけなら

import System
main = do args <- getArgs
print args

こんな風に書ける。ちなみにこのプログラムは簡単に書くと

import System
main = getArgs >>= print

こんな風にも書ける。簡単バージョンだな。
またgetArgsの出力は文字列のリスト、[String]で得られる。

ところでGHCの吐き出すexeファイルにファイルを1つ、もしくは複数個D&Dすると
その絶対パスのリストが得られることが分かった。
これをうまく解析してやれば、Ver.1のプログラムをもう少し改善出来そうだ。
というわけでドラッグ&ドロップされたファイルのパスのリストの取得&出力をするプログラムを書く。

import System
main = do getArgs >>= printArgs
getChar >>= print

printArgs :: [String] -> IO ()
printArgs (f:l) = do putStrLn f
printArgs l
printArgs [] = putStr ""

このような関数定義はパターンマッチをうまく使うと綺麗に書ける。
(パターンマッチについてはまだ書いてないのでそのうち)

少し解説すると、一つ一つは簡略バージョンの描き方。
またgetCharとprintのコンビは、コマンドプロンプトがすぐに閉じないようにするために入れてある。


これをすると、1つまたは複数個のファイルをD&Dしたとき、そのパス名リストを出力してくれる。
また今回はgetArgsを使ったが、どうもgetContentsのままでもこれは出来るらしく
こういったのを組み合わせてブログの記事リスト作りプログラムを改良する。


category of Haskell:
Haskell】とても簡単なHaskellプログラムについて
Haskell】標準入力(stdin)を読み込むために
Haskell】結構頻繁に使う関数などの話
Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法
【Haskell】C言語の構造体のようなものをHaskellで利用する
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.0)
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.1)

【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.1)

さて、前回の記事で作ったHaskellプログラム。いろいろと突っ込みどころがあります。
要するに「標準入力から読み込んで、HTMLソースを標準出力に出す」という制限の部分です。
だってあなた(自分)、ブログ書くときにコマンドプロンプト使うの?っていうことですよね。
確かにコマンドプロンプト自体はよく使うものですが、別にブログを書くときにまで使いたくはないですよね。
というわけでここを改善していきます。最低限利用できるプログラムにします。


どのように改良するのか。せっかくGHCはexeファイルを吐き出してくれる。
ですからファイルから読み込んでファイルから書き出すようないっぱしのプログラム形式にしてみたいわけです。
exeファイルとして使えるようになるので


  • exeファイルと同じところにあるsrc.txtというテキストファイルにリストを書いておく
  • このリストを読み出して、HTMLソースを作成する(前回のプログラム)
  • 最終的にexeファイルと同じところにあるhtmlsrc.txtに書き出す


このようにすればまだ使える感じがしてきますね、プログラムっぽいです。
というわけで前回のプログラムをうまく再利用しながらやっていきます。


前回のプログラムを再利用できるところ
getHtml :: String -> String
getHtml h = let wh = words h
number = head $ wh
title = head $ tail $ wh
in do "<a href=\""
++ hreftp
++ number
++ ".html\"><strong>" ++ title ++ "</strong></a>"

リストからHTMLソースにする部分。ここはそのまま使えます。
結局標準入力と標準出力を使う代わりにファイル入力とファイル出力を使えばいいのです。


ファイル入出力はIOパッケージで利用できるのですが、いわゆる例外が発生します。
こんなファイルありませんよ?とか、このファイルには書き込めませんよ?とかいうやつです。
こういった実行時例外などへの対処は、本当はちゃんと書かないといけないところだと思います。
がしかし、結局自分が使うプログラムであるから、手の抜けるところは手を抜くという方針です。
よってこういったところは少し目をつぶり、とにかく簡単なファイル入出力をします。
まず次のように宣言します。

import IO
infile = "src.txt"
output = "htmlsrc.txt"

IOを使えるように、また入力ファイル名と出力ファイル名を固定しておきましょう。
さて、次のようにファイル入出力を行うプログラムは書けます。

main = do cs <- readFile infile
outhandle <- openFile output AppendMode
hPutStrLn outhandle header
hPutStr outhandle $ unlines $ map getHtml $ lines cs
hClose outhandle

簡単ながら説明していきましょう。

1.もっとも簡単でシンプルなファイル入力
標準入力を取ってくるgetContentsというものがありました。
また実行時引数を取ってくるgetArgsというものもあります。
これと似たように、簡単なファイル入力にはreadFileという関数が利用できます。

cs <- readFile filename


このようにすることで、あたかもgetContentsしているようにファイルから入力できます。
前に言っているとおり、細かい例外の処理などはありません。
このようにして持ってきた入力csをver.0のように処理することでHTMLを生成できます。

2.簡単なファイル出力の準備
出力時、今回は現在存在しているファイルの末尾に書いていくという追加書き込みを利用します。
C言語風に言うと”a”というモードで、HaskellではAppendModeという表現がされます。
こういったものを扱うために、ハンドラと呼ばれるものを経由した書き込みを行います。
ハンドラの宣言は次のように行われています。

outhandle <- openFile output AppendMode


変数名outhandleで、openFileというのがデータコンストラクタです。
データコンストラクタについては【Haskell】C言語の構造体のようなものをHaskellで利用するで書きました。
このデータコンストラクタにファイル名とハンドラのモードを与えることでファイル書き込みのための準備をします。

3.実際にファイル出力をする場所
標準出力putStrLnとputStrに対応するファイル書き込みようの関数がhPutStrLn及びhPutStrです。

hPutStrLn handler STRING
hPutStr handerl STRING


のようにすることでSTRINGをhandlerで設定しているファイルに書き込むことが出来ます。


4.後片付け
書き込みを行った後、hCloseという関数でハンドラの後処理を行います。
これを行わないと書き込みがちゃんと完了しないといった現象が発生します。


実行
さて、このようにして作成したプログラムに、リスト

3 【Haskell】とても簡単なHaskellプログラムについて
8 【Haskell】標準入力(stdin)を読み込むために
36 【Haskell】結構頻繁に使う関数などの話
37 【Haskell】高階関数と型の定義について
489 【Haskell】リストの処理について
509 【Haskell】C言語の構造体のようなものをHaskellで利用する
511 【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.0)


をsrc.txtとして置いておき、プログラムを実行して生成されるファイルhtmlsrc.txtからのコピペを張って終わります。


category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法
【Haskell】C言語の構造体のようなものをHaskellで利用する
【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.0)

【Haskell】Haskellを使ってブログに微妙に役立つプログラムを書きたい(Ver.0)

Haskellの話のように、連続的に書いているような記事はよくあります。
そのとき、たとえばHaskellの記事であれば


category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法
【Haskell】C言語の構造体のようなものをHaskellで利用する


こんな感じの記事リストを付けていることがある。
実はこのリストは、いつもちまちまとHTMLのコードを自分で手打ちしている。
これを円滑に作成出来たらいいなぁと思ったことがあった。
せっかくHaskellを勉強しているので、これを題材としてプログラムを書いてみる。


このリストを作成するときに、次のような記事番号とタブ、記事タイトルが書かれたテキストファイルを適当に作る。

3	【Haskell】とても簡単なHaskellプログラムについて
8 【Haskell】標準入力(stdin)を読み込むために
36 【Haskell】結構頻繁に使う関数などの話
37 【Haskell】高階関数と型の定義について
489 【Haskell】リストの処理について
509 【Haskell】C言語の構造体のようなものをHaskellで利用する

このリストから上のリンクリストを作成するようなHaskellプログラムを作成する。
とりあえず簡単にするために、標準入力からこのリストを読み込み、標準出力へ出力する。
つまり

mbh.exe < src.txt > href.txt

のように使えるようにする。
まずは次のようにヘッダの部分(水平線の表示)と、リンクのひな形部分を定義しておく。

header = "<hr size=\"1\">category of Haskell:"
hreftp = "http://parabola0.blog86.fc2.com/blog-entry-"

標準入力を読むため、次のように書く。

main = do cs <- getContents
putStrLn header
putStrLn $ unlines $ map getHtml $ lines cs

標準入力から得られる上のテキストファイルのリストを一つずつ処理する。
つまり数値+タブ+タイトルの文字列からHTMLのリンクタグを返す関数getHtmlを作る。

getHtml :: String -> String
getHtml h = let wh = words h
number = head $ wh
title = head $ tail $ wh
in do "<a href=\""
++ hreftp
++ number
++ ".html\"><strong>" ++ title ++ "</strong></a>"

letなど、多少適当に書いていると思う。
(まだここら辺はあまりなれていないのでよく分からない感じもあったり)
これを利用すると次のようなHTMLのソースが出力される。

<hr size="1">category of Haskell:
<a href="http://parabola0.blog86.fc2.com/blog-entry-3.html"><strong>【Haskell】とても簡単なHaskellプログラムについて</strong></a>
<a href="http://parabola0.blog86.fc2.com/blog-entry-8.html"><strong>【Haskell】標準入力(stdin)を読み込むために</strong></a>
<a href="http://parabola0.blog86.fc2.com/blog-entry-36.html"><strong>【Haskell】結構頻繁に使う関数などの話</strong></a>
<a href="http://parabola0.blog86.fc2.com/blog-entry-37.html"><strong>【Haskell】高階関数と型の定義について</strong></a>
<a href="http://parabola0.blog86.fc2.com/blog-entry-489.html"><strong>【Haskell】リストの処理について</strong></a>
<a href="http://parabola0.blog86.fc2.com/blog-entry-509.html"><strong>【Haskell】C言語の構造体のようなものをHaskellで利用する</strong></a>

これをコピペすると、はいブログで使ってるようなリストのできあがり。


category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法
【Haskell】C言語の構造体のようなものをHaskellで利用する

【Haskell】C言語の構造体のようなものをHaskellで利用する

Haskellは関数型言語であって、代入という概念がない
Schemeでも基本的にそうなのだけれども、Schemeの場合 set! などのように
!マークがついた命令=書き換えの命令というものが存在したので、代入のようなことは出来る。

HaskellもC言語のようにInt、Char、String、Boolなどいろいろな型がある。
それらを組み合わせて一つの型のように、C言語で言う構造体のように使うことも出来る。
ただし代入は出来ないので、最初に設定した値を変えることは出来ない。


まずC言語の構造体
typedef struct book{
char* name;
int pages;
} Book;

このように書けば、新しいBook型のデータの固まりが使える。
それぞれ

Book book;
strcpy(book.name, "Test Book Name");
book.pages = 100;

のように使える。

Haskellの場合
data Book = Book { name   :: String,
pages :: Int}

このように書く。ただ単にStringとIntの組ですよーということが言いたいのならば

data Book = Book String Int

とも書けるが、少し扱いにくくなる。
結局、扱いやすくするなら上のように、変数名にラベルをつけておくのがいい。

このとき
=の左辺にあるBookは新しい型の名前である。
=の右辺にあるBookをBook型のデータコンストラクタと呼ぶ。
型の名前もデータコンストラクタも、英大文字で始まる必要がある。

データコンストラクタは関連づけられている値を作成するときに使う関数のようなもの。
(細かいこと:データコンストラクタ自体も値を持つ。)
この場合、データコンストラクタBookはBook型の値を作るのに利用できる。
ただしデータコンストラクタの名前と型の名前は一致する必要はない。
ここでは分かりやすくするために一致させて書いている。

実際に値を作る
Haskellには代入がない。
よって最初に作成したときの値がずっと使われる。
最初に作成するのは、データコンストラクタを利用して次のように書ける。

book :: Book
book = Book "Usual Haskell Programming" 372

まずbook::Bookによって、変数bookがBook型であることを示す。なくてもいい。
次の一文によってデータを作成する。

Book "Usual Haskell Programming" 372


によって、nameの値がUsual Haskell Programmin、pagesの値が372であるBook型の固まりを作成している。
これをbookというBook型の変数に束縛することで、データを作成したことになる。

作成した型を利用する
型をdata構文によって作成したとき、自動的にアクセサが作られる。
アクセサとは型からそれぞれのメンバの値を取ってくるための関数のようなもの。
アクセサはメンバの名前と同じ名前の関数によって利用できる。つまり

name → name :: String を取得する関数
pages → pages :: Int を取得する関数


となる。

この関数は次のように利用できる。

main = do putStrLn $ show $ pages book
putStrLn $ name book
printBook

printBook = do putStr $ name book ++ " all pages:"
putStrLn $ show $ pages book

実行結果は次のようになる。

372
Usual Haskell Programming
Usual Haskell Programming all pages:372



372はpages関数で、次の名前はname関数で出力したモノ。
最後の文は自分で作った関数で出力したモノである。


category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について
【Haskell】コマンドライン引数を得る方法

【Haskell】コマンドライン引数を得る方法

Haskell本の中の話。

標準入力のByte数を数える
main = do cs <- getContents
print $ length cs


標準入力のWord数を数える
main = do cs <- getContents
print $ length $ words cs



その他の話
あるリストの先頭、それ以外、部分列を返す関数が出てきた。
Prelude> print $ head [0, 1, 2, 3, 4]
0
Prelude> print $ tail [0, 1, 2, 3, 4]
[1,2,3,4]


部分列を返す関数tailsはListをimportすると使える。
Prelude> import List
Prelude List> print $ tails [0, 1, 2, 3, 4]
[[0,1,2,3,4],[1,2,3,4],[2,3,4],[3,4],[4],[]]



importの話。
Preludeというのはもっとも基本的なパッケージ。
Argsパッケージを用いると実行時引数を利用できる。

import Args
main = do args <- getArgs
putStrLn $ unword $ args


こんな感じ。
unwordはリストをバラバラにして文字列としてしてくれる。
空白で連結する。
getArgsで引数を取得すると、その引数のリストにしてくれる。





category of Haskell:
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について
【Haskell】リストの処理について

【Haskell】リストの処理について

過去の記事
【Haskell】とても簡単なHaskellプログラムについて
【Haskell】標準入力(stdin)を読み込むために
【Haskell】結構頻繁に使う関数などの話
【Haskell】高階関数と型の定義について



今回はリスト処理の話の総括です。

リストの型
リストには同じ型のモノが入ります。IntならInt、StringならStringのリストです。
それぞれ、[Int]、[String]のような型になり、空リストでは[]で表されます。

文字列とリスト
文字列には改行である\nが入ります。
\nに対して、文字列Stringを文字列のリストへ分割する関数とその逆の関数があります。
第一回などで使っているlines、unlines関数です。

Prelude> print $ lines "aiueo\nkakikukeko\nsasisuseso\n"
-->["aiueo","kakikukeko","sasisuseso"]
Prelude> print $ unlines ["a", "i", "u", "e", "o"]
-->"a\ni\nu\ne\no\n"
Prelude>



リストの処理
リストの長さはlength関数で調べられます。

Prelude> print $ length ["a", "i", "u", "e", "o"]
5



リストの頭n個をとってくる関数はtake関数です。

Prelude> print $ take 2 ["a", "i", "u", "e", "o"]
["a","i"]



リストはreverse関数でひっくり返すことが出来ます。

Prelude> print $ reverse ["a", "i", "u", "e", "o"]
["o","e","u","i","a"]



Tabや空白を元にして単語のリストに分けることも出来ます。

Prelude> print $ words "this is a pen."
["this","is","a","pen."]
Prelude> print $ words "a\nb\nc\n"
["a","b","c"]



リストのリストを連結して一つのリストにする。
リストのリストのリストを連結してリストのリストにする。
このようにリストのレベルを一つ減らす関数はconcatです。

Prelude> print $ concat [ [1,2], [3], [4,5], [6]]
[1,2,3,4,5,6]
Prelude> print $ concat [ [[1,2]], [[3]], [[4,5]], [[6]]]
[[1,2],[3],[4,5],[6]]



あるxをn個含んだリストを作るにはreplicate x nとします。

Prelude> print $ replicate 5 7
[7,7,7,7,7]



リストを生成する演算子として : があります。
おそらくどちらか一方はリストでなければなりません。

Prelude> print $ 1:[2,3]
[1,2,3]




リスト処理にもいろいろありますね。

Page Top

訪問者

お引っこし。 http://parabola.sblog.jp/

プロフィール

parabola0

Author:parabola0
Twitter用ですが…。
プロフィール

最新記事
最新コメント
最新トラックバック
カテゴリ
月別アーカイブ
検索フォーム
リンク

このブログをリンクに追加する

QRコード
QRコード
RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。