fugafuga.write

日々のログ

すごいH本 part19

ラムダ式

ラムダ式とは、1回だけ必要な関数を作る時に使う無名関数です。

通常、高階関数に渡す関数を作るためだけに使われるらしい

バックスラッシュを書いてからこのようにする。

(\{引数1} {引数2} -> {関数本体})

普通、ラムダ式は括弧で囲むとのこと。

numLongChains :: Int
numLongChains = length (filter (\xs -> length xs > 15) (map chain [1..100]))

実行結果

*Main> numLongChains
66

カリー化と部分適用の動作がよくわかってないと、必要ないところでラムダ式使いがちになるらしい。

*Main> map (+3) [1,2,3,4]
[4,5,6,7]
*Main> map (\x -> x + 3) [1,2,3,4]
[4,5,6,7]

これは部分適用のほうが可読性が高い例

ラムダ式は任意の数の引数を取ることができる

*Main> zipWith (\a b -> (a * 30 + 3) / b) [5,4,3,2,1] [1,2,3,4,5]
[153.0,61.5,31.0,15.75,6.6]

ラムダ式でもパターンマッチができる

*Main> map (\(a, b) -> a + b) [(1,2),(3,4),(5,6)]
[3,7,11]

ラムダ式でパターンマッチが失敗したら、ランタイムエラーが発生するので注意すること。

addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z

addThree' :: Int -> Int -> Int -> Int
addThree' = \x -> \y -> \z -> x + y + z

関数はデフォルトでカリー化されているので上の2つの関数は等価らしい。 この場合、前者のほうが可読性が高い。 ラムダ式を括弧なしで書いた場合、->の右側のすべてがそのラムダ式に属する。

カリー化の方がよい場合もある。

flip' :: (a -> b -> c) -> b -> a -> c
flip' f = \x y -> f x y

こちらのほうが「引数を入れ替えた関数を返す」ということがコードから伝わりやすい。

flip で一番多い使い方は、引数として関数のみ、もしくは関数と引数を1つだけ渡し、生成された関数を map や zipWith に渡すという方法がある。

*Main> zipWith (flip (++)) ["love you", "love me"] ["i ", "you "]
["i love you","you love me"]
*Main> map (flip subtract 20) [1,2,3,4]
[19,18,17,16]

所感

vim2hs\λに勝手に変えてくれる機能でカーソル位置がずれまくってたので以下の設定をOFFにした。

let g:haskell_conceal = 0

以前わからんと言っていた flip の具体的な使い方が出てきた。flip subtract 20はわかりやすい。が、自分で書くとなると書けないと思う。

周りの Haskeller はわからんと言ってたら教えてくれるのでとても感謝しています。ありがとう。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る