【Haskell】簡単なプログラムをHaskellで試してみる!

どーも!

たかぽんです!

今回はHaskell...という言語を触ってみたいなぁと思ったので、簡単なプログラムを書いて遊んでみようと思います!

それでわやっていきましょう!

なぜHaskell...?

さて、なぜ唐突にHaskellなんだ?って感じですが...w

これに関してはただただ筆者の興味関心ですw

仕事でも使っていないので全く知識ゼロですが...

以前関数形プログラミングというプログラミングパラダイムをチラッと学んだことがあり、その時にHaskellは純粋関数型プログラミング言語と呼ばれているようでいつか触ってみたいと思っていたんですよね。

一応メジャーなJSとかでも実装方法に気をつければ実現ができたりするようです。

そこらへんは今後試してみるとして...

今回は一旦普通にHaskellをさわってみよう!という感じですね!

Haskellで簡単なプログラムを試す!

さて、それではHaskellを試していきます!

まずはHaskellを実行するために必要なコンパイラ、インターフェイスをインストールします。

brew install ghc

上記を実行するとそれだけでOKです!

無事ghc, ghciのインストールが完了したら...

taka@Taka haskell % ghci
GHCi, version 9.6.2: https://www.haskell.org/ghc/  :? for help
ghci> putStrLn "Hello, World!"
Hello, World!

上記のようにして対話型インターフェイスで実行ができるはずです。

いつものやつですね。

とりあえず世界にこんにちわしときます。

次はファイルに記載してコンパイル、実行ファイルを実行...といった形で動かしてみます。

そのため、対話型インターフェイスは下記コマンドで止めておきます。

ghci> :quit
Leaving GHCi.
taka@Taka haskell %

haskellを試す!

では、今からHaskellを試してみます!

まずは簡単なプログラムを作ってみました。

main :: IO ()
main = do
    print $ myAdd 5 3
    print $ mySubtract 5 3
    print $ multiply 5 3
    print $ divide 5 3
    print $ factorial 5

-- 四則演算の基本関数
myAdd :: Int -> Int -> Int
myAdd x y = x + y

mySubtract :: Int -> Int -> Int
mySubtract x y = x - y

multiply :: Double -> Double -> Double
multiply x y = x * y

divide :: Int -> Int -> Double
divide x y = fromIntegral x / fromIntegral y

-- 階乗
factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n - 1)

最低限説明しておくと、

myAdd :: Int -> Int -> Int
myAdd x y = x + y

上記は関数の形定義になります。

myAdd関数はInt型の引数を二つとり、最後の一つが関数が返す型で、同じくIntを返す...という定義になっています。

そして、その下の定義が関数の実態ですね。

引数x, yに対する処理を書いています。

それを四則演算分、用意している形です。

実際に実行すると...?

taka@Taka haskell % ghc hello.hs
[1 of 2] Compiling Main             ( hello.hs, hello.o ) [Source file changed]
[2 of 2] Linking hello [Objects changed]
taka@Taka haskell % ./hello
8
2
15
1.6666666666666667
120

上記のようになります。

今回は最低限の形で実行しているので、"ghc hello.hs"でビルドし、実行ファイルを作成後、"./hello"で実行するかたちですね!

ここで終わってもいいのですが、せっかく試したので、少し関数型の理解にチャレンジしてみます...!

関数型プログラミングの特徴について

まず最初に、関数型プログラミングの特徴について自分なりにまとめておきたいところなのですが、これに関しては従来多々議論が交わされているようですが、難しいところのようです。

ので、とりあえず難しいことは考えず触ってみようと思います!

ちなみに、そのやんごとなきこととか筆者としても色々考えさせられた示唆に富んだ記事があったので是非軽くみてみてください。

部分適応(カリー化)を試してみる!

さて、簡単なHaskelは試したのですが、次は部分適応を試してみます。

カリー化とよばれたりするようです。

例えばですが、足し算をするには引数が二つ必要ですが、二つの引数は渡さず、一つだけ適当な値を渡します。

そして、もう一つの引数を引数とした新しい関数を定義すると、足し算の関数を使って、常に一定の値を足す関数を定義することができたりします。

簡単な例を以下に示します。

-- 部分適応を用いて関数を定義
add10 :: Int -> Int
add10 = myAdd 10

calcTax :: Double -> Double
calcTax = multiply 0.1

入力された値に10を足す関数、0.1を掛ける関数...といった具合ですね!

main = do
    print $ add10 5
    print $ calcTax 1500

上記の形の場合...

taka@Taka haskell % ./hello
15
150.0

出力は上記のようになります。

数学的に表すと以下のようなイメージですね...!

add10(x) = add(10, x)
calcTax(x) = multiply(0.1, x)

// 一般化すると以下のようなイメージ
g(x)=f(a,x)

次は関数合成についてみてみます。

関数合成を試してみる!

さて、次は関数合成です。

数式で表すと以下のような形なのですが...

(f∘g)(x)=f(g(x))

例えば

f(x) = x!
g(x) = x + 10

だったとしたら、f(g(x)) = g(x)! = (x+10)!

といった具合ですね。

Haskelの場合はこの合成は'.'で関数をつなげるだけなのですが...

Haskellの関数合成の.演算子は、右側の関数を先に適用し、その結果を左側の関数に渡すように動作します。

例えば以下のように定義をすると...

add10ThenFactorial :: Int -> Int
add10ThenFactorial = factorial . add10

先ほどの"(f∘g)(x) = f(g(x)) = g(x)! = (x+10)!"といった形になります。

適応順は一番右からになるので、まず最初に"x+10"が行われ、その後factorial関数に引数として足した結果が渡され、(x+10)の階乗が計算される形ですね。

taka@Taka haskell % ./hello
15
150.0
39916800

この合成を使えば、極論、四則演算の基本的な式の適応順を組み替えることで、大抵の複雑な計算は関数として定義することができます。

つまり、基本的な関数としてあらゆる機能を実装しておけば、あとはその機能をレゴブロックのように合成して組み合わせることで、色々できるようになるようですね。

是非先ほど作った関数を色々組み合わせて自分好みの関数を作ってみてください!

まとめ

さて、今回はHaskellを用いて簡単なプログラムを試してみました!

合わせておまけ程度に関数型プログラミングも齧ってみました。

せっかくHaskellを触って、ちょっと楽しいなと感じたので、AtCoderなどで問題を解く...とかやってみるのは楽しいかもしれないですね...!

また、関数型プログラミングもまだほんの少ししか触れていないのでまだまだ理解も浅いです。

せっかく初めて触る純粋関数型言語なので、ちょっと色々触ってみて試してみたいなと思います!

それでわ!

おすすめの記事