mike-neckのブログ

Java or Groovy or Swift or Golang

ふつうのHaskell 8章

単なる読書メモ

無名関数

書き方

\n -> n * n

使い方

map (\n -> n * n) [1,2,3,4]

関数合成

書き方

before

lineCount:: String -> Int
lineCount s = length $ lines s

after

lineCount:: String -> Int
lineCount = length . lines

部分適用

例:5の倍数を得る関数

二つの引数をとって掛け算をする関数を部分適用するパターン

-- 二つの引数をとって掛け算をする関数
multiply:: Int -> Int -> Int
multiply x y = x * y
-- 5の倍数を得る関数
multiplyWith5:: Int -> Int
multiplyWith5 = multiply 5

セクションを使ったパターン

multiplyWith5:: Int -> Int
multiplyWith5 = (* 5)

変数を削減する

例:[String]に添字を加える

before

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

intermediate

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

after

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

関数合成と部分適用でリファクタリング

before

import System.Environment
import Data.List
-- main
main = do
    as <- getArgs
    cs <- getContents
    putStr $ fgrep (head as) cs
-- grep
fgrep:: String -> String -> String
fgrep ptn s = unlines $ filter match $ lines s
    where
        match:: String -> Bool
        match line = any prefixp $ tails line
        prefixp:: String -> Bool
        prefixp line = ptn `isPrefixOf` line

step1

prefixpを部分適用(セクション)で書き直し

prefixp:: String -> Bool
prefixp = (isPrefixOf ptn)

step2

matchprefixpを組み込む

match:: String -> Bool
match line = any (isPrefixOf ptn) $ tails line

step3

matchの引数を省略

match:: String -> Bool
match = any (isPrefixOf ptn) . tails

step4

fgrep$を消す

fgrep:: String -> String -> String
fgrep ptn = unlines . filter match . lines
    where
        match:: String -> Bool
        match = any (isPrefixOf ptn) . tails

step5

matchを独立させる

match:: String -> String -> Bool
match ptn = any (isPrefixOf ptn) . tails

step6

fgrepwhereをなくす

fgrep ptn = unlines . filter (match ptn) . lines

after

import System.Environment
import Data.List
-- main
main = do
    as <- getArgs
    cs <- getContents
    putStr $ fgrep (head as) cs
-- grep
fgrep:: String -> String -> String
fgrep ptn = unlines . filter (match ptn) . lines
-- match
match:: String -> String -> Bool
match ptn = any (isPrefixOf ptn) . tails