Haskell > 本 > 入門Haskellプログラミング > LESSON 3
#html{{
table border="0" cellpadding="5"><tr><td valign="top"><a href="https://www.amazon.co.jp/exec/obidos/ASIN/4798158666/vertex9-22/" target="_blank"><img src="" border="0"></a></td>
td> </td>
td valign="top"><a href="https://www.amazon.co.jp/exec/obidos/ASIN/4798158666/vertex9-22/" target="_blank">入門Haskellプログラミング</a><br>Will Kurt<br>翔泳社<br>2019-07-31<br>¥ 4,104</td></tr></table>
}}
#html{{
div class="panel panel-danger">
<div class="panel-heading">キーワード</div> <div class="panel-body">}}
#html{{
</div>
/div>
}}
書式
\x -> x
本書、p.26の図3-1には間違いがある。
「関数の引数(複数の場合もある)」から伸びている線は、右側のxに向かっているが、正しくは左側のxに向かっていなければならない。
ラムダ関数の書き方の例
Prelude> (\x -> x * 2) 4 8
型を確認してみます。
Prelude> :t (\x -> x) (\x -> x) :: p -> p
Prelude> :t (\x -> x * 2) (\x -> x * 2) :: Num a => a -> a
#html{{
div class="panel panel-danger">
<div class="panel-heading">キーワード</div> <div class="panel-body">}}
#html{{
</div>
/div>
}}
(参考)
補助関数とは、関数定義の内部でのみ使用する部分的な関数のことです。
補助関数を作成することで、複雑で分かりにくいプログラムの構造を簡潔にして可読性を向上することができます。
また、処理毎に分割することはプログラムを再利用しやすく、保守性のあるものにします。
なお、補助関数を内包する親となる関数は「最上位関数」と呼ばれます。
Haskellにおける補助関数の定義方法は「let」と「where」の2通りありますが、whereを使うほうが一般的といえます。
どちらを使用しても問題ありませんが、混在していると可読性が悪くなるため、統一して利用することが推奨されています。
(p.29)
Haskellには、where句の代わりに使用できるlet式と呼ばれるものがあります。
素朴な疑問です。
基本
let 変数/関数 in 式という書式で、ローカルな変数や関数を定義できる。
letは式なので結果を返す。
whereとの違い
whereと似ているが以下の点が異なる。
- どこでも書ける。
- whereではガードをまたぐことが出来るが、letで定義したものはinの中でしか参照できない。
好みの問題もあるが、基本的にはwhereを使って、必要な場合はletを使うのが良さそう。
「ガード」による違いがあるみたいですね。
基本はwhereを使っておくことにしておきたいと思います。
プログラミング学習では専門用語が次から次へと出てくるので、後で混乱しないように意味を押さえて覚えておきたい。
ラムダ関数は、別名で「無名関数」とも言ったりする。(言語によって違うのだろうか?)
無名関数とは
無名関数とは、一時的に使用するために使い捨てる前提で生成する、名前の無い関数です。
Haskellではラムダ式(ラムダ関数)を記述することで無名関数を定義することが出来ます。ラムダ関数(lambda calculus)とは
ラムダ関数とは、文字ラムダ (λ) を使った式によって表記する関数です。
ラムダ式で記述された関数は、一時的な使い捨ての関数として利用することができます。
なお、ラムダ関数は、匿名関数(無名関数)とも呼ばれます。
些細なことだけど、素朴な疑問。
なぜ無名関数はラムダ関数という名称が与えられているのか?
そもそも「ラムダ関数」とか「ラムダ計算」の「ラムダ」ってどこから出てきたのか?
名前の由来
ラムダ式に用いられる記号 λ に由来するわけだが、この λ 自身の由来については2説あり、真偽についてはあまりはっきりしていない。由来がある説
Rosserという人が1984年に以下のように報告している。
Russell と Whiteheadが、関数を抽象化するときの記号に「^x(HTMLの仕様上表記できないが、âのaをxにしたもの)」を用いていた。Alonzo Churchは、この表記法にちなんで、「∧x」という記号を使用するようになった。その後印刷しやすいように「∧」の代わりに「λ」を使用するようになった(ちなみにλの大文字はΛ(≠∧)である)。由来なんかない説
Alonzo Church自身は後年「とにかく記号が必要だったからたまたまλを選んだ」と語っており、この話を信じるなら特に由来はないということになる。一般には紙面で報告された「由来がある説」の方が信頼性が高いということになるが、紙面とはいえ他人がした報告である。一方こちらはAlonzo Church本人の言葉であり、そう聞いた人が1人だけというわけでなく2人いるということなので、こちらもそれなりに信憑性が高い。
λ算法はなぜλなのかについては、次の説が有名である。
Alonzo Churchがλ算法を考えた時、RusselとWhiteheadが Principia Mathematicaで束縛変数を表すのにカレット^を 使っているのに倣ったが、1行でタイプする都合上カレットを前に出し ^x f(x) とし、それが λx f(x)となった。
どうやら、Church自身が両方の説(^説と偶然説)を語っているようだ。
可能性としては、
- λの選択は偶然だったが、Harald Dicksonへの手紙ではジョークのつもりで もっともらしい話をでっち上げたらそれが広まってしまった
- Principia Mathematicaからインスピレーションを得たといえばそうなのだが、 記号の起源なんてどうでもいいと思っていたので後の方ではただ偶然ということにしておいた
あたりだろうか。
「^」この記号は何ていう名前なんでしょうか?
サーカムフレックス(英語: circumflex)または曲折アクセント(きょくせつアクセント)は欧文用の「山」型の記号で、フランス語、ポルトガル語、ベトナム語、ルーマニア語、エスペラント、日本語のローマ字などで用いられるダイアクリティカルマーク(発音区別符号)の一種。
別名、キャレット (caret)、ハット記号 (hat [symbol])。
ただしUnicodeでは、「キャレット」は別の文字 U+028C の名称になっている(そちらが原義)。
有間隔のサーカムフレックス「ˆ」はASCIIに含まれ、他の文字を修飾しない独立した記号として使われる。
ダイアクリティカルマーク(英語: diacritical mark)または発音区別符号(はつおんくべつふごう)は、ラテン文字等の文字で、同じ字形の文字であるが、発音が区別されるべき場合に文字に付される記号のこと。
キャレット・脱字符号 (英: caret) は、校正で、脱字の挿入を指示する記号。挿入位置の下(縦書きでは横)に山形を書き、その下に挿入したい文字を書く。なお、単なる脱字でなく長い語句を挿入したいときは、キャレットの代わりにブレースを使う。
コンピュータの文字入力画面で、入力文字の挿入位置、つまり、カーソルとしても使われる。言葉どおりキャレット型のもののほか、点滅する縦棒などさまざまな形式のものがある。また、制御文字を表現するのに、キャレットとアルファベットを使ったキャレット記法が用いられる。
また、ASCIIの5E「^」(サーカムフレックス)や、数学記号で論理積や外積を表す「∧」(ウェッジ)を、字形の類似からキャレットと呼ぶこともある。
「キャレット」という記号は、正確には下側に位置する山形の記号だった。
上側に位置する山形の記号は、「サーカムフレックス」とか「ハット記号」という名前の別の記号だった。
^ ←サーカムフレックス(上側に寄っている山形の記号) ‸ ⁁ ←キャレット(下側に寄っている山形の記号)
両方とも単体で見た場合には形がそっくりだから、サーカムフレックスをキャレット(カレット)と呼ぶ場合もある。
ややこしいですね!
で、ラムダに話を戻すと、最初キャレット(本当はサーカムフレックス)を使って「^x」とか書いていたのを「λx」と書くようになった。
それが「ラムダ」という記号が登場するきっかけであり、ラムダ計算とかラムダ関数とか呼ばれる由来になったわけですね。
特に深い意味はなくて、気まぐれで使っただけみたいなので、ここは「なぜラムダなんだろう?」と悩むところではないのでしょう。
ただの定義というか、「へー、そういうもんなの?」と軽く受け流して、次行ってみよう!
この問題の解き方が分からなかった。
そこでHaskellのラムダ関数について、他の説明を参照して、知識の過不足、ズレを修正したいと思い検索してみた。
↓この連載記事は一度全部に目を通しておいた方がいいかも。
単純には、Haskellの問題じゃなくて、ラムダ関数(無名関数)の使い方の知識が不足しているのだろう。
高階関数の扱い方とかが何かズレているのかもしれない。