読者です 読者をやめる 読者になる 読者になる

メモメモ

Haskell

8章の関数についてだよ><おいらの理解用だから激しく間違ってると思うよ><><。

部分適用の応用→変数の削減

部分適用というのは、引数全部を指定するのではなく、引数のいくつかを渡す方法。これをやった返ってくる結果もまた関数である。

こんな関数が

zipLineNumber :: [String] -> [(Int,String)]
zipLineNumber xs = zip [1..] xs

のように書き代えられていく。

zipLineNumber :: [String] -> [(Int,String)]
zipLineNumber = zip [1..]

何でこういうのが可能なのか?最初の関数はこんな感じで書き代えることができる。

zipLineNumber :: [String] -> [(Int,String)]
zipLineNumber xs = f xs
    where f = zip [1..]

zipに一つしか引数が与えられていないのは何とも不安な気分になるが、これでよい。なぜかと言えば部分適用をしているから。zip関数に引数一つだけを渡した関数、のようになっているということ。だからfは値、というより関数である*1

これからzipLineNumber関数ってのはfの別名だよねーってことになり、fをそのまま置き代えると2つ目の書き方ができるというわけ。

ポイントフリースタイル

  • 関数を関数で定義するコーディングスタイル
fgrepの改良

関数合成と部分適用のセクションを使った。

import System
import List

main = do args <- getArgs
          cs <- getContents
          putStr $ fgrep (head args) cs

fgrep :: String -> String -> String
fgrep pattern = unlines . filter match . lines
  where
    match :: String -> Bool
    match = any (pattern `isPrefixOf`) . tails
    -- 二項演算子とセクションなのでかっこが必要っぽい
    -- 関数合成も使ってる
8.6練習問題1

ポイントフリースタイルで書く。

import Char

main = do putStrLn "hello"
          print $ map lstrip ["   fjaskdfj","f asdjkfjas","  fjak"]

lstrip :: String -> String
lstrip = dropWhile (==' ')
8.6練習問題2

何も考えずに書いた。mapだらけで[これはひどい]。

import Char

main = do putStrLn "hello"
          print $ map reverse $ map lstrip $ map reverse ["   fjaskdfj  ","  f as   djkfjas","  fjak"]

lstrip :: String -> String
lstrip = dropWhile (==' ')

と思ったらリストに対する処理じゃなくてよい感じか。

てか、一回一回やらなくって、String -> Stringの処理を作ってまとめてmapすればいいじゃんか。関数合成を使う。

import Char

main = do print $ map rstrip ["   fjaskdfj  ","fjas  "]

rstrip :: String -> String
rstrip = reverse . lstrip . reverse

lstrip :: String -> String
lstrip = dropWhile (==' ')
8.6練習問題3
import Char

main = do print $ map strip ["   fjaskdfj  ","fjas  "]

strip :: String -> String
strip = rstrip . lstrip

rstrip :: String -> String
rstrip = reverse . lstrip .reverse

lstrip :: String -> String
lstrip = dropWhile (==' ')
8.6練習問題4

ん、ここの練習問題ではラムダ出てこないじゃないか。。。

main = do cs <- getContents
          putStr $ lastNLines 2 cs

lastNLines :: Int -> String -> String
lastNLines n = unlines . reverse . take n . reverse . lines

*1:関数も値になるんだっけ?束縛??