Chapter1 Getting Started〜Haskell モジュールの写経

  • とにかく写経してGS.hsなるファイルを作る
  • Stackがデフォルトで作ったLib.hsをまねて作る
  • 作成した「わり切れるかの判定」関数も外から参照可能にする
  • Lib.hsと同じくsrcディレクトリに置く
  • app以下にあるMain.hsにGS.hsをインポートさせ、GS.hsのsomeFuncGS関数を実行させる
  • .cabalファイルにGS.hsのありかを教える必要もある
module GS
    ( someFuncGS
    , divides
    , ld
    , ldf
    ) where

{-
module GS ()の()の中はエクスポートする関数を決める
-}

someFuncGS :: IO ()
someFuncGS = putStrLn "GS"

divides :: Integer -> Integer -> Bool
divides d n = rem n d == 0

{-
divides 3 6 --- True
divides 3 -6 --- error
divides 3 (-6) --- True
divides 3 $ -6 --- True
3 `divides` 6 --- True
-}

{-
nの最小約数は、k(k=2)以上n以下の整数であって、
kから調べ始めて、divides k nがTrueであるとき
そのkが最小約数
-}

ld' :: Integer -> Integer
ld' n = ldf' 2 n

ldf' :: Integer -> Integer -> Integer
ldf' k n | divides k n = k
         | otherwise = ldf' (k+1) n

{-
探索範囲を少し狭める
あるkで割り切れないことがわかっているとき
もしも、k^2 > nならば
k+1 .. nにはnを割り切る数はないので
その場合はnが最小約数
-}
ld :: Integer -> Integer
ld n = ldf 2 n

ldf :: Integer -> Integer -> Integer
ldf k n | divides k n = k
        | k^2 > n = n
        | otherwise = ldf (k+1) n
        
{-
素数判定
1未満のときはエラー
1のときは1
2以上の整数であって、最小約数が自身であるとき
それは素数
-}

prime0 :: Integer -> Bool
prime0 n | n < 1 = error "non positive"
         | n == 1 = False
         | otherwise = ld n == n
         
{-
リストにある整数の中から最小のものを取り出す
空のリストではエラーを返す
要素数1のリストの場合はその値を返す
要素数が2以上の場合は、先頭要素を
先頭以外の要素の最小値とを比較し
その小さい方を返す
リストは (x:xs) のように先頭とその他にわけられる
(,)も含めてリストだということだろう
-}

minIntList :: [Int] -> Int
minIntList [] = error "empty"
minIntList [x] = x
minIntList (x:xs) = min x (minIntList xs)

{-
リストを先頭から探索し
指定した値に出会ったら
それを取り除く
-}
removeFst :: Int -> [Int] -> [Int]
removeFst m [] = []
removeFst m (x:xs) | x == m = xs
                   | otherwise = x:(removeFst m xs)


               

{-
ソートの方法1
リストの最小要素を確認し
その最小要素と
最小要素を除いて要素数が1つ減ったリストをソートしたリストと
結合する
-}

srtInts :: [Int] -> [Int]
srtInts [] = []
srtInts xs = m : (srtInts (removeFst m xs)) where m = minIntList xs

{-
ソートの方法2
論理は同じで書き方を変える
最小要素をmとし、そのmは
in 以下で定められるように振る舞う
-}

srtInts' :: [Int] -> [Int]
srtInts' [] = []
srtInts' xs = let
                 m = minIntList xs
              in m : (srtInts' (removeFst m xs))

{-
平均
有理数は整数と整数の比で表す
n % m = n/m
-}

average :: [Int] -> Rational
average [] = error "no element"
average xs = toRational (sum' xs) / toRational (length' xs)

{-
リストの和と長さはいずれも要素の個別処理と
その累積和
ただし和を取る要素の値が異なる
-}

length' :: [Int] -> Int
length' [] = 0
length' (x:xs) = 1 + length' xs

sum' :: [Int] -> Int
sum'[] = 0
sum' (x:xs) = x + sum' xs

{-
特定の値の要素数を数える
-}

count :: Char -> String -> Int
count _ [] = 0
count x (y:ys) | x== y = (1 + (count x ys))
               | otherwise = count x ys
               
{-
数列
S(n) = f(S(n-1))
suuretsuはn番目の値を返す
suuretsusは0番から無限大番までの値を返す

take 20 (suuretsus (+2) 2)
-}

suuretsu :: (Int -> Int) -> Int -> Int -> Int
suuretsu f x 0 = x
suuretsu f x y = f (suuretsu f x (y-1))

suuretsus :: (Int -> Int) -> Int -> [Int]
suuretsus f x = map (suuretsu f x) [0..]
  • Main.hsの変更
module Main where

import Lib
import GS

main :: IO ()
main = someFuncGS
  • mathBookStack.cabalファイルの変更
library
  hs-source-dirs:      src
  exposed-modules:     Lib
                     , GS
  build-depends:       base >= 4.7 && < 5
  default-language:    Haskell2010
  • ここまでやって
stack install
mathBookStack-exe
  • 結果
GS
  • ghciでGS.hsを使ってみる
  • ..../mathBookStack で(他で、でもよいが)
stack ghci
  • としたうえで
:load ./src/GS.hs
*GS> divides 3 6
True
*GS> divides 3 6 --- True
True
*GS> divides 3 -6 --- error

<interactive>:10:1: error:
    &#8226; Non type-variable argument in the constraint: Num (a -> Bool)
      (Use FlexibleContexts to permit this)
    &#8226; When checking the inferred type
        it :: forall a. (Num (a -> Bool), Integral a) => a -> Bool
*GS> divides 3 (-6) --- True
True
*GS> divides 3 $ -6 --- True
True
*GS> 3 `divides` 6 --- Truedivides 3 6 --- True
True
||
-その他の知識
--関数オブジェクト(小文字始まり)の型確認
>||
*GS> :type divides
divides :: Integral a => a -> a -> Bool
    • aをIntegralのそれとしたときに、dividesは引数としてaを2つ取り、Boolを返す
    • Integralは大文字始まりなので、型とかクラスとかそういうもののはずだが、実際、何かと言えば
*GS> :info Integral
class (Real a, Enum a) => Integral a where
  quot :: a -> a -> a
  rem :: a -> a -> a
  div :: a -> a -> a
  mod :: a -> a -> a
  quotRem :: a -> a -> (a, a)
  divMod :: a -> a -> (a, a)
  toInteger :: a -> Integer
  {-# MINIMAL quotRem, toInteger #-}
  	-- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’
    • classであることがわかり、Realであって Enum(列挙可能)であるaがあったとして、quot以下、toIntegerまでの7つの関数を持つ。ただし、Realがすでに定義を持つので、quotRem,toIntegerのみの定義が必要。また、IntegralクラスにはWord(符号なし整数), Integer, Intなるタイプがあることもわかる