
はてなキーワード:高階関数とは
ここ1年で初めてはてなブックマーク日毎の総合人気エントリ入りしたドメインからのホットエントリ、ブクマ数順トップ30
| ブクマ数 | タイトル | ドメイン |
|---|---|---|
| 2212 | 声明文 -脳外科医竹田くん | dr-takeda.hatenablog.com |
| 1409 | KyotoU Channel | www.channel.pr.kyoto-u.ac.jp |
| 1393 | DeNA南場智子が語る「AI時代の会社経営と成長戦略」全文書き起こし |フルスイングbyDeNA | fullswing.dena.com |
| 1294 | 子供の不機嫌への対処法 -感情の考察、日常の幸福 | kosakimomo.hatenablog.com |
| 865 | 中国で失踪 | safeguarddefenders.com |
| 822 | トップページ|オウム真理教問題デジタルアーカイブ | www.moj.go.jp |
| 817 | 僕のタスク管理2025年版:ChatGPTとNotionでいい感じに毎日を過ごす | mozlog | kannnonn.com |
| 750 | SNSで規制すべきは組織的な書き込み - 続・はてなポイント3万を使い切るまで死なない日記 | kawango.hatenablog.com |
| 665 | まだ人間が議事録書いてるの?日本語特化の文字起こしAI『kotoba-whisper-v2.0』がスゴいらしい | data.wingarc.com |
| 659 | 海外「日本人は深煎りコーヒーを好む」日本独自のコーヒー文化に対する海外の反応 : すらるど -海外の反応 | sow.blog.jp |
| 639 | 自分のOSSのマルウェア入り偽物を作られたので通報した - 酒日記はてな支店 | sfujiwara.hatenablog.com |
| 591 | 球団からのお知らせ | www.yakult-swallows.co.jp |
| 563 | NHKシステム開発・移行中断の件について | jp.newsroom.ibm.com |
| 528 | 突然Yahoo!IDが停止されてeBookJapanも利用不可になった件 -Privatter | privatter.net |
| 499 | 押井守監督が20年目の“今だから”語れる「イノセンス」の真実 そして本作を“今”劇場で観る意義とは? | anime.eiga.com |
| 481 | 「うちの鍋は、もうこれだけでいいよ!」夫に言わしめた鍋は「2つの調味料」を入れるだけ。締めラーメンまで絶品 | kufura(クフラ)小学館公式 | kufura.jp |
| 474 | 当社に対する訴訟の提起について |重要なお知らせ |株式会社サンリオ | corporate.sanrio.co.jp |
| 470 | NOT AHOTELのビジネスモデル - 続・はてなポイント3万を使い切るまで死なない日記 | kawango.hatenablog.com |
| 464 | なぜあなたのウェブサイトは遅いのか | mizchi-20250213-devsumi.pages.dev |
| 457 | map / filter などの高階関数よりも古典的な for文の方が読みやすいと感じるあなたへ | gakuzzzz.github.io |
| 426 | 生成AI時代の音声入力ツール:SuperWhisperのすすめ - うみのーと | umiyosh.hatenablog.com |
| 420 | 音楽の新陳代謝が止まって「ダサい」がなくなったことの功罪 - 森の掟 | guatarro.hatenablog.com |
| 414 | Rustで進化するPayPayのスケーラビリティ | blog.paypay.ne.jp |
| 407 | マキネッタ、完全に理解した - ちなみに | blog.nishimu.land |
| 370 | 【動画】田代まさしさん「覚醒剤はフジテレビのあるADから『いいのありますよ』と誘われた」 | sn-jp.com |
| 369 | 死神 -ヤマシタトモコ /死神 | OURFEEL(アワフィール) | ourfeel.jp |
| 345 | 【トラブル】成田空港会社が契約終了を警告、「みんなで大家さん」に借地リスク浮上 | nfm.nikkeibp.co.jp |
| 344 | NotebookLMWeb Importer -ChromeWeb Store | chromewebstore.google.com |
| 319 | draw.ioでレイヤーを使ったらAWS構成図が捗ったお話 | tech.anti-pattern.co.jp |
| 313 | SQL道場 -SQLの実践的な学習サイト | sql-dojo.com |
ChatGPT 4o
この文章の主張は、「バグを減らすために for 文を避け、map や filter を使うべきだ」というものだが、これは一面的な見方とも言える。
確かに、関数型プログラミングの恩恵を受ける場面は多く、副作用を減らし、データの不変性を維持することでバグを減らせる。しかし、for 文が全て悪いわけではなく、状況によっては適切な選択肢になる場合もある。
また、「How だとか What だとかどうでもいい」という主張には疑問が残る。アーキテクチャや設計方針を軽視しすぎると、長期的な保守性や拡張性に問題が生じる可能性があるため、バランスが重要だ。
Claude3.0
総括:
この記事は実践的な観点から重要な指摘をしていますが、やや極端な主張も含んでいます。プログラミングパラダイムや技術の選択は、以下の要素を総合的に判断して行うべきです:
Gemini2.0
for文よりもmapやfilterなどの高階関数を使う方がバグが減るという記事の主張には概ね賛成です。ただし、for文が完全に不要というわけではなく、オブジェクト指向でもカプセル化を用いてデータの書き換えを制御できます。TypeScriptは型のチェックだけでなく、Classを用いたオブジェクト指向プログラミングも可能です。
3AIにだいたい共通している主張
・関数型言語の目的の一つにバグを減らすというものがあるというのは同意
・letを使わない(厳密には副作用の排除)はバグを減らす効果がある
・悪いのはfor文ではなく副作用だが、可変な変数が必ずしも悪いとは限らない
・TypeScriptの型チェックを使うとバグが減る
「プログラミングに必要なのはググる力だ」などとまことしやかに言われます。が、これは嘘なので、プログラミング初心者は(中級者以上も)真に受けないで下さい。そして、プログラミング教育に携わる人は、こういう有害な嘘を広めるのはやめて下さい。
なお、ここでいう「プログラマ」とはプログラミングを仕事にする人、または作成したプログラムを公開する人を指しています。純粋に趣味でプログラミングをしており、ソースコードもソフトウェアも公開するつもりの無い人は、どんな方法でプログラミングをしようと自由です。
プログラマに(プログラマに限らず)必要なのは、自身の専門分野に関する基礎的かつ体系的な知識です。それらが不足していては、「ググる」ことさえままなりません。英語で喩えれば、時制や不規則動詞という概念を知らずに辞書を引いて、「Isawhim yesterday. 」の「saw」をのこぎりのことだと思い込むようなものです。要するに、調べたい事項が何に関するものなのかを理解していなければ、調べようがないのです。
それでは、プログラミング初心者にとって必要な基礎知識は具体的にどのようなものでしょうか。
まず当然ですが、自分が使っているプログラミング言語やフレームワークの機能は一通り知っている必要があります。組み込みのデータ型や制御構文はもちろん知らなければいけません。高階関数、クラス、非同期処理等の発展的な機能も知る必要があります。言語だけではなく、パッケージマネージャ、タスクランナー、単体テストツール等の周辺ツールの理解も必要です。また、「コードコンプリート」とか「Effective ○○」のような書籍に書いてあるような設計・コーディングのベストプラクティスも知らなければいけません。要するに、現代のプログラミングの「常識」は全て知っている必要があります。
そもそも「そういう機能が存在する」と認識して初めて「調べる」ことができるのです。列挙型という機能の存在を知らずに「Javaで列挙型はどう書くのだろう」と調べることはできません。非同期処理の存在を知らずに、「JavaScriptで非同期処理はどう書くのだろう」と調べることはできません。
では、そのような一通りの知識を身に着けるためには、どのようなリソースから学ぶべきでしょうか。
逆に、Wikipedia、Qiita等の個人が趣味で書いた記事、プログラミングスクールの記事、プログラミングスクールや家庭教師、etcを主体に学ぶのはやめるべきでしょう。
もちろん、特定の話題について調べる過程で、非公式の情報に行き着くことはあるでしょうが、そこで使用されているライブラリ等の仕様については、必ず公式ドキュメントで裏を取るべきです。
時々、こういった正式なドキュメントを読むことが、初心者にはハードルが高いと言う人がいます。しかし、冒頭で述べたようなプログラミングを仕事にしようとしている人達が、こういうことができないのはおかしいです。
実際、公式ドキュメントを読むことはそれほど難しいことではありません。有名な言語やライブラリ等のドキュメントであれば、高校程度の数学力英語力とある程度のコンピュータ操作の経験があれば、理解できるように書かれています。その程度の素養も無いのにプログラマ(特に職業プログラマ)になろうとすることが、そもそもおかしいのです。運動が苦手なのにプロスポーツ選手になろうとするようなものです。
てほしい。
プログラミングを理解できない人はいます。いい加減この事実を認めて下さい。
こういう話になると、やれ「教え方が悪い」だとか、やれ「順序立てて学べば誰でも理解できる」などという輩が出てきますが、それは事実に反します。
まず、プログラミングは手順さえ覚えれば誰でもできるようになると言うものではありません。プログラミングを理解するには、一定レベルの論理的思考能力を要します。それが身に付いていない人には無理です。また、どんなレベルの人でも、プログラミングで分からないことは出てきます。プログラミングができる人は、そういう時に、
といったことをして解決する力があります。そういう試行錯誤をしない人や、複雑だったり抽象的な概念を突き詰めて考えることをしない人に、プログラミングを理解するのは不可能です。
たとえば、再帰関数が分からないとしましょう。具体的に何が分からないのかは人によって異なります。たとえば、
など。これらを解決するには、自分で仕組みを突き詰めて考えたり、コードを書いてデバッグしてみたり、調べたり人に聴いたりするしかありません。講師が気の聞いた喩え話などをすれば、たちまち疑問が氷解するなどということはあり得ません。
また、一口に「プログラミングを理解する」と言っても、そのレベルは様々です。
最初の2〜3程度が「自分の思うプログラミングの全て」な人が、軽々しく「プログラミングは誰でも理解できる」などと思わないでいただきたいのです。それは実用上は全然足りていません。サンプルコードをググりながら、やっとこさVBAで複数のエクセルファイルを集計できる程度の人が「プログラミングできる」気になっていては困るのです。
上記の大部分は、自分のプログラムを他人に見せるつもりのある人なら十分に習得しておく必要があります。ましてや、プログラミングで飯食おうと言う人間が、FizzBuzzに毛の生えたようなコードを読み書きするのに精一杯で、効率や保守性に気を配れないのは論外です。
上記の特に後半に書いたようなことは、誰にでもできることではありません。ちょっとしたコツや方針を守れば機械的にこなせるというものではなく、技術力の高い人でも熟考を要することです。彼らは、そうした高度なことを正しく考える力があるから、技術力が高いのです。そういう力は、誰かに用意してもらったカリキュラムを受動的にこなすだけではまず身に付きません。
取り上げた技術は、本格的な開発でも役に立つもので、最も学習コストが低いものを選んだ。
重要度が低いものは載せていない。たとえばHTMLとCSSなんてググりながら書けば全く問題ない。Bootstrapなどのフレームワークも全くやる必要はなく、仮に就職先で使っていたら覚えればいい。
逆に言えば以下に挙げる技術は、そもそも概念自体がプログラミングにとって普遍的なものであり、(基礎的な部分を)調べながら使うようではエンジニア失格ということ。
基本的に現在では、バックエンド・フロントエンド・運用保守全てができないエンジニアに価値は無い。
以下に挙げた技術(①⑤⑥は他の言語やフレームワークで代替可能)が身に付いていなければまともな企業に就職することは難しい(もちろん、下らない業務システムを下請けで作ってる底辺企業には入れるだろうが)。
経験者でも、これらができない/わからないのは、相当恥ずかしいことだと思った方がいい。
特定の言語やフレームワークの書き方を知っていること自体に意味は無い。
重要なのは、他の言語やフレームワークにも共通する基礎を理解すること・保守性やセキュリティなどの品質を高める使い方ができること。
この2つは習得が容易だし、今覚えておけば向こう10年腐ることはないだろう。
基本的な構文や、よく使う標準ライブラリは勿論、高階関数・クラス・非同期処理等の発展的な機能も知り尽くしていなければならない。
言語のみではなく、パッケージ管理、単体テスト、タスクランナー等の周辺ツールの使い方も熟知している必要がある。
また、「リーダブルコード」や「コードコンプリート」に書いてあるような良い作法も身に付ける必要がある。
Gitを使えないのはプログラマーとして論外。細かい機能は調べればよいが、
多くの場合、本番環境やテスト環境はLinuxサーバーであるから、以下のような基本的な概念と使い方を知っておく必要がある。
環境構築、CI、デプロイなどは、現在コンテナを使って行うことが当たり前になっている。
これも細かいことをすべて覚える必要はないが、Dockerfileの書き方や、docker-composeの使い方などは知っておかなければいけない。
Flaskは、数あるWebフレームワークの中で最も簡単。本当に呆れるほど簡単で、Pythonさえ書ければすぐにアプリを作れる。
フレームワークを覚えること自体が重要なのではなく、Web開発の基本を習得することが重要。HTTP、ルーティング、データベース、SQL、認証、セッション管理などは当然すべて覚える。
データベースは、就職したらMySQLやPostgreSQLなどを使うことが多いかも知れないが、今はPythonの標準ライブラリにあるSQLite3を使えば十分。
作ったアプリを公開したければ、「Heroku」などにデプロイするのが良いだろう。
ブコメで指摘をいただきました。HerokuではSQLite3は使用できないようです。公式のドキュメントに従ってPostgreSQLを使用して下さい。
SQLite3はファイルにデータを持てる簡易DBなんだけど、Herokuにデプロイしてもストレージ的な使い方はできないから、結局PostgreSQLを使う必要あるから注意してね。(DAOを丸ごと書き換える羽目になる)
参考:https://devcenter.heroku.com/ja/articles/sqlite3
今の時代、フロントエンドをフレームワークなしで作るのはただのバカ。
2021年現在、実用的なフロントエンドのフレームワークはReactとVueしかない。Vueの方が少し簡単なのでこちらを選んだが、JavaScriptをしっかり理解しているなら大差は無い。
フロントエンドには膨大なパッケージ群があって全部覚えるのは大変だが、とりあえずまずはVueを完璧に使えればいい。Webpackの設定などは既存のものを流用すればいい。
アルゴリズムは全てのコンピュータ技術の基礎であり、絶対に知っていなければならない。
高速フーリエ変換のような高度な数学は必要ないが、クイックソートや木構造のような基本的なアルゴリズムは当然、その性質を知っていなければならない。
それらは言語の組み込み関数や標準ライブラリでも使われており、理解していなければ、それらの機能を正しく使うことができない。
また、プログラムを読み書きする際には、そのコードの計算量を見積もれなければならない。
セキュリティは言うまでもなく学ばなければならない。
有名な脆弱性や攻撃手法(XSS・SQLインジェクション・CSRFなど)が何だか理解していて、その対策を実装できなければならない。
各種暗号化技術や署名などについても、実装の詳細は知らなくていいが、共通鍵暗号や公開鍵暗号などの特性は理解する必要がある。
認証やパスワード管理などを実装する際は、当然ベストプラクティスに従わなければならない。
Permalink |記事への反応(37) | 07:52
プログラミングはセンスです。センスの無い人がプログラマになると、他のすべての人に迷惑がかかります。だから、センスの無い人は絶対にプログラマにならないで下さい。
プログラミングのセンスが無い人や、プログラミングをやったことの無い人は、知識を得たり経験を積んだりすれば、誰でも「良いプログラマ」になれると思っているようですが、無理です。
というのも、センスの無いプログラマの問題は、知識や経験の不足ではないからです。センスの無いプログラマの救いようの無い問題は「頭がおかしいこと」なのです。
題材は何でもいいのですが、具体的なコードを見た方がイメージがつきやすいと思いますので、とりあえず以下の問題を考えます。
住民のリストが与えられるので、背の低い順に男女ペアにしたリストを作って下さい。ただし、男女の数は同数であるとします。
const makePair = (persons) => {constmales = persons.filter(person => person.sex ===MALE)constfemales = persons.filter(person => person.sex ===FEMALE)const compareHeight = (a, b) => a.height - b.heightmales.sort(compareHeight)females.sort(compareHeight) returnmales.map((male, idx) => [male,females[idx]]) // 男女の数は同数}
この例はJavaScriptなので高階関数を使っていますが、仮にそういう機能が無かったとしても、
一方、センスの無いゴミプログラマは、以下のような名状しがたきコードを書いてきます。
function pair(psns) { var i = -1; varcnt = 0; var flg = psns[0] &amp;&amp; psns[0].sex; var j = -1; var tmp = null; for(i = 0; i < psns.length; i++) { //console.log('■■■■■■■■■■■■■■■■■■■■BEGIN ■■■■■■■■■■■■■■■■■■■■') //console.log(psns, 'i=' + i, 'cnt=' +cnt, 'flg=' + flg); if(psns[i].sex == flg) { //console.log('cnt: ' +cnt + '->' + (cnt+1));cnt++; } else { j = i -cnt + 1; //console.log('swap ' + i + '<-->' + j); tmp = psns[j]; psns[j] = psns[i]; psns[i] = tmp; i = j - 1; // <-理由は分からないが、i = jだと上手くいかない(byXXXX)。cnt = 0; flg = flg ==MALE ?FEMALE :MALE; while(j> 1) { if(psns[j].height < psns[j-2].height) { //console.log('swap ' + j + '<-->' + (j-2)); tmp = psns[j-2]; psns[j-2] = psns[j]; psns[j] = tmp; } j -= 2; } } //console.log(psns, 'i=' + i, 'cnt=' +cnt, 'flg=' + flg); //console.log('■■■■■■■■■■■■■■■■■■■■ END ■■■■■■■■■■■■■■■■■■■■') //console.log('') } for(i = 0; i < psns.length; i++) { //console.log('■■■■■■■■■■■■■■■■■■■■BEGIN ■■■■■■■■■■■■■■■■■■■■') j = Math.floor(i / 2); //console.log(psns, 'i=' + i, 'j=' + j); tmp = psns[i]; if(!(i % 2)) { psns[j] = [null, null]; } if(tmp.sex ==MALE) { psns[j][0] = tmp; psns[j][1] = psns[i+1]; } else { psns[j][0] = psns[i+1]; psns[j][1] = tmp; } i++; //console.log(psns, 'i=' + i, 'j=' + j); //console.log('■■■■■■■■■■■■■■■■■■■■ END ■■■■■■■■■■■■■■■■■■■■') } psns.splice(psns.length / 2, psns.length);}こんなコードのメンテナンスは御免被りたいです。一見して配列の要素を入れ替えていることが分かるだけで、実装を全て読まなければ(いや読んでも)処理の意図が全く分かりません。また、たとえば「i = j - 1」が間違って「i = j」などと書かれていてバグを起こしたとしても、原因を突き止めるのは困難を極めます。
さて、このコードは具体的に何がいけないのでしょうか。長すぎることがいけないのしょうか。変数名が分かりにくいのがいけないのでしょうか。引数を破壊的に変更しているのがいけないのでしょうか。不要なコメントが残っているのがいけないのでしょうか。よく見ると、ソート処理で車輪の再発明をしていたり、「j」や「tmp」などが場所によって意味が違うカメレオン変数になっていたりしますが、それがいけないのでしょうか。どれも正しいですが、それらを逐一直したところで、本質的な解決にはならないでしょう。
後者のコードはもはや「ここを直したら良くなる」とかいうレベルを超えています。たしかに、問題を具体的に挙げることはできます。このコードの致命的な問題が、凝集度の低さと、単一責任の原則(SRP)違反にあるのは間違いありません。しかし、後者のコードを書いてくる人に、
「住民リストを男女に分ける処理や、リストをソートをする処理、2つのリストをまとめる処理は、この問題とは独立して意味のある操作だから、別の関数として抽出しましょう。その方がコードの見通しがよくなるし、一部の処理を修正したときの影響も小さくなるし、単体テストも書きやすくなります」
なんて言ったって聞く耳を持たないでしょう。
そもそも、こういうコードを書く人は、この処理自体を「pair」なんて関数に抽出すらしません。まだこの問題では入出力のフォーマットが明確に定義されているので、他人が1から書き直せますが、実際のプロダクトでは、無数の副作用を起こす数千行のコードの迷路を彼の脳内フォーマットのデータが通るわけです。もちろん、テストコードなんてありません。
つまり、指摘をしても絶対に直らないのです。いくら言語の優れた機能やベストプラクティスを紹介しても、馬の耳に念仏。それらの利点を理解できるだけの脳みそが足りていないのです。
どうして、同じ処理を実装するのに、ここまでの違いが生じるのでしょうか。
これは、プログラミングの技術の問題ではありません。既に述べた通り、ふつうの人なら、特定の機能の有無とか知識の程度にかかわらず、ふつうのコードを書くのです。なぜなら、ふつうの人にはそちらの方が楽だからです。つまり、前者のコードは別に何か卓越した技術を身につけた結果書けるようになるものではなく、まともな感覚さえ持っていれば、プログラミング初心者にとっても前者のコードの方が書きやすいのです。
つまり、後者のようなコードを書いてくる奴というのは、現実世界の捉え方が常人とは著しくずれているのです。要するに、「頭がおかしい」のです。この病気はもう直りません。だから、センスの無い人は絶対にプログラマにはならないで下さい。
Permalink |記事への反応(20) | 20:14
意識低い企業内研究者です。プログラミングはサブウエポン。だけど趣味でも勉強してる。
働き方改革のせいで早く帰れって言われて、酒のみながら今これを書いてる。
C言語とかC++は・・・これで作らないといけないものが今の所ないし、これでお金を稼ぐのはハードルが高いし、
WindowsのAPIを使って複雑なプログラムを作りたいわけじゃないのでwhileとかifとか基本的な構文だけ覚えるだけで満足。
組み込みプログラミングではC言語はいまだに現役。お金も普通に稼げると思うよ!次代のCOBOLと化しそうで怖いとこはあるけど。
Javaは・・・使える人が多いからあえて今から学習しなくてもいいような気がする。
文字列の結合だけでもダメやり方と良いやり方があるらしくて、何かPHPのようにその言語特有のセオリーみたいなのを覚えるのが面倒くさそうなので入門の時点で学習するのをやめた。
セオリーとかあるかもしんないけど速度とか気に揉むまえに書いて測れ。たいていは杞憂か、あるいはCPUパワーで殴れるから。
Goは・・・HTTP/2が使えるから学習してる。他の言語だとnghttp2をインストールしないといけないようなのでGo便利だと思ってる。
ライブラリの選択肢が多すぎるのでこういうのが作りたいってときにこれを使うのがいいよっていうのが知りたい。
GUI作るのにライブラリありすぎてどうやって選べばいいのかさっぱりわかんない。
Goでデータベース扱うならこれを使え、だけどMySQLしか使わないならこれを使え、あっSQLiteならこっちのライブラリ使うと便利みたいなこういう情報が欲しい。
GoでGUIつくるの?あんまり普通じゃない気がする。軽量プロセスのうまみがそんなない(詳しい人に否定されそうだけど)
普通にC#(mono/.net)かwebアプリにするかで良くないか?
ただ、言語をあれもこれも覚えるのって僕は意味があるのかなという思いもある。
広く浅く学習するより、狭く深くいきたいとおもうけど、paizaでCランクしか取れない。
twitterで有名な人てやっぱりSランクとか余裕なのかな、こういうのもいろんなプログラマーに聞いてみたい。
一応著名なプログラマーをTwitterでフォローしてるけど、ご飯の画像を載せてたり、若者の僕には通じない寒いギャク連発してたり、ロリっぽい画像をRTしてたりと、twitterはメインの情報収集としては利用してない。
twitterやってるプログラマーって勉強会とかオフ会に参加してるようなリア充の人ばっかりなので、肩身が狭いから自分からリプは送ったりはしない。
ファンがたくさんいるのに最近ニコ生配信してくれないchokudai先生みたいに、アルゴリズムを学ぶのがいいのかな。
アルゴリズムは使うものだ書くものではない!高階関数とかテンプレートプログラミングとかその辺勉強するといい。
あと計算が制限時間内に終わるなら総当たりが最速で品質も高いぞ。
どうしてVimかというとプラグインが多いしIDEっぽくできるから。
Vimってハードル高いイメージあったけど、入門記事がたくさんあるので助かっている。
NetBeansが重すぎるんだよ。補完ボックスが表示されるの遅すぎて警告メッセージが出た。補完ボックスが表示されるまで7秒ぐらい経過すると警告メッセージが表示されたと思う。
Vim知らない。Linux使うならVimかemacs使えるだろみたいな雰囲気あるけど、GUIならgedit,CUIならnanoでいいよね。
パソコンのスペックもどのくらいのものを用意したらいいのかわからない。
10年前のVistaが搭載されていた頃の家電量販店で一番安かったCeleron 1コアメモリ1GBグラボなしノートだからプログラミングに向いてないのかもしれない。
VirtualBox上のubuntuでMySQLをコンパイルすると2時間20分ぐらいかかった記憶がある。
CPUが1コアなのでコンパイル中にそれ以外の作業なんて重くてできない。
スペックにお金をかけることで時間の節約ツールの選択肢が増える
EclipseなどのIDEが支障なく使えるレベルのスペックってどのくらいするんだろう。
3年前のCore i7,SSD, 8GB。最近はもっぱらJupyter。
Pythonは・・・・機械学習する上で避けて通れないけど、今のPCだと無理。
Pythonはいいぞ、機械学習だけじゃなく計算系はエクセルじゃなくてJupyter使う。でも周りはエクセルつかってる、勿体ない。
使ってないけど最先端の研究では機械学習使って当たり前感があってそろそろヤバい。
僕は中学生の頃、いじめにより心の余裕なんてなかったから勉強どころではなかったけどもっと英語の勉強しておけばよかったと後悔している。
迷宮にいる感じ。
なんとなく、プログラミングじゃないほうがいい気がするなあ。
関数型言語なんて、多くのプログラマにとって猫に小判、豚に真珠ということだ。
コミュニティの文化が独自とか、学習コストが高いとか言われているが、それは本当の理由じゃない。
本当の理由は、オブジェクト指向言語すら使いこなせていないのに、関数型言語なんて必要ないという理由だ。
オブジェクト指向言語を使い倒していれば、同じ概念を関数型言語ではずっと楽に実現できることにすぐに気づく。
逆にオブジェクト指向言語で無理して使っている概念(例えば高階関数など)がないと利点に全く気づけない。
普段余計な一手間を加えてでも、実現したい便利で強力な概念を、そもそも使っていないのでは、関数型言語を書く意味はない。
関数型言語でもオブジェクト指向言語でも、やることは変わらないとずっと思ってきたし、それなのになぜ関数型言語が普及しないのか、ずっと不思議だった。
毛の壁以降、色んなところであーだこーだ再定義言われてるけど、結局名前が悪いんだよなぁ。
どちらかというとオブジェクト指向の方が「何もかもサブルーチン(ただし値を覚えていてくれるおまけつき)」で、関数型の方が「何もかもが値(関数も)」なんだけど、まず名前からだと逆っぽく聞こえる。
加えて、この二つの概念が対立すると思われてしまうけれど、んなこたーないのはjavascript見れば分かる。何もかも値かつサブルーチン、でOK。
両立しにくいのは、オブジェクトの概念と高階関数の概念ではなく、オブジェクト指向言語が採用してきた型システムと、関数型言語が採用してきた型システムだ。
つまりC++やらJavaやらが採用してきたサブタイプ多相をベースにしたクラスによる型付けと、ML系言語が採用してきた代数的データ型が噛み合わない。致命的に。
いやまぁScalaは頑張って統合したけど、コンパイル遅いわ書き方次第で型チェックが無限ループになるわで、色々と無茶しやがって感ある。
当方いわゆるweb系プログラマ30代。大学は卒業に失敗しているので学歴としては高卒。年収は800万に届かない程度。web系プログラマはインターネット上で目立っている有名プログラマも多くて、彼らと自分を比べると絶望するくらいに自分のスキルは低い。でも最低限の能力はあると思う(参考までに、GitHub 上で一番starをもらっているリポジトリは 14star というレベルの実力。150star くらいあるリポジトリに PullRequest を送って取り込んでもらったことがあるという程度)。
で、このレベルの人間が周りの年上プログラマを見てると、「なんだ、こいつらが食って行けるなら、俺は楽勝で食って行けるじゃん」って思うことが多い。「その辺のちょっとだけできる大学生のほうがよほどまともだぞ」みたいなコード書く人間がのうのうとプログラマとして食って行ってる。ほんとうにひどいやつらが多くて、一番笑えたのが「経験豊富だしどん欲に学習してきたのでどんな言語も対応できます」って言ってた39歳の人間で、彼は「高階関数」という概念がまったく理解できなかった。「関数ポインタを引数で渡すみたいなもんですよ」って言ったら「関数ポインタとか実務で使うことないしwwwwwww」みたいに返されて絶句した。よく2ch のプログラマ板で「if と for がわかればなんでも書けるし」みたいなこと言ってるやついるけど、「あーこういう人間がああいう書き込みするんだな」って変に納得できた。
でもそのひとは会社からそこそこの金をもらってた。それ見て思ったんだけど、いくらひどいコードであっても、「とりあえず動くものが作れる」っていうのはスキルの一種であることには違いないんだな。正直絶対に一緒に働きたくないし、そいつが書いたコードは絶対にメンテしたくないけど、メンテナンス性がどれだけ大事かってことを理解している経営層っていうのは少ないみたいで(これは経営層じゃなくてむしろプログラマ側のコミュニケーションスキルの問題の気がする)、とりあえず動いているように見えるものを作ることさえできれば、お金を握っているひとからお金を引き出すことは可能なんだな、ってことをそいつを見て理解した(またこいつが「コード読めないひと」をだますのがうまいんだ)。
で、ここで初めてタイトルにつながるんだけど、ようするにそれが「手に職」ってことなんだな、って思ったんだ。
詐欺ってのは言い過ぎにしても、「手に職」って言われる職業ってだいたい寡占なんだよね。たとえば資格がないとできない職業は資格を持った人間の寡占状態にある。プログラムを書くのに資格は必要ないけど、プログラムの読み書きは未だに特殊技能で(これは教育の問題だと思う)、コードのメンテナンス性の善し悪しを判断できるのもまたプログラマだけであるという意味でやっぱり寡占状態にある。
自分はプログラマだからこの寡占状態に恩恵にあずかっている側で、おかげで「ひとまず職にあぶれることはなさそうだな」っていう安心を得ることができているんだけど、この寡占状態って絶対不健全で、たとえば誰の目にも数字という形でわかりやすく現れてくる営業(一方からの勝手な見方で、営業の世界にもいろいろあるのかもしれない、イメージで語ってゴメン)だったら、「あいつ数字悪いな、切ろうぜ」ってなるレベルの人間が「まあでも我々にはプログラマの世界はわからないからなぁ、彼は優秀っぽい雰囲気があるし」みたいな感じでお金をもらうことができるんだもん。
だからやっぱり「手に職」って詐欺っぽい要素があると思う。だってそもそも「手に職があれば食うに困らない」って時点でおかしいじゃん。最低レベルの営業職と、最低レベルの技術職、どっちも最低のはずなのに「俺は技術職で手に職があるから困らない」ってどう考えてもおかしくない?やっぱり詐欺だよこれって。
Permalink |記事への反応(10) | 03:24
これ読んでも関数型分からないけど、入り口の前あたりに立つために
プログラマとしての引き出しが増える。
って書くと「そんなもんどんなプログラミングテクニックだって一緒だわ」って言われそうだけど、でもそうとしか言い様がない。
とりあえず、オブジェクト指向と同じで、プログラムを構造化して、複数のレイヤーに切り分けて部品化していくテクニックだとは言える。
ただオブジェクト指向とは大分切り口が違う。何ていうか、割と直交する切り口でプログラムの構造を切り分けていく。
なので、関数型とオブジェクト指向と両方憶えるだけで、大分切り口の引き出しが増える。
オブジェクト指向と関数型両方憶えると、プログラマとしての引き出し増やすのに効率が良い、って思えば良いかも。
オブジェクト指向は、プログラムの各部品を「あれの中のこれの中のそれの中にあるあれ」みたいな感じで組み合わせる。
部品が更に細かい別の各部品で構成されていて、それぞれの部品が噛み合わさって、複雑な一つのプログラムを構成するような切り方。
関数型言語は、プログラムの部品を「あれをした物にこれをした物にそれをした物にあれをする」みたいな感じで組み合わせる。
もっというとプログラム全体を簡単に記述するできるDSLがあって、そのDSLを簡単に実装するためのDSLがあって、DSLの入れ子構造で一番小さい部品はシンプルな関数、みたいな切り方。
ケースバイケース。
ではあるんだけれど、シンプルな部品を大量に組み合わせて構成するのがしっくりくるならオブジェクトで、部品数が少ないんだけど一個一個が複雑な動作する構成にしっくりくるのが関数型……かも?
関数型言語たる条件として「関数が第一級オブジェクト」ってのがあるんだけど、関数が第一級オブジェクトだとイミュータブルなデータを素直に扱える。
で、イミュータブルなデータ構造使うと色々便利、ってことで実例として一番出てくるという。
関数型言語のエポックメイキング的な言語が三つくらいあって、元祖のLispとその流れ汲んだMLとMLの一種で関数型をある種の到達点に持っていったHaskellって感じ(独断と偏見)。
で、このうちのMLって奴が、プログラミング言語に型システムがついてるんじゃなくて、型システムにプログラミング言語がついてきた存在だったりする。
型で色々やるために生まれたわけで、まぁなんというかそもそも型と密接な関係にあって、Haskellもその流れを汲んでて、こいつが超有名になった、って感じ。
おかげさまで、型使って色々やったりする方法が日々考えられているわけです、静的型付関数型の世界では。
関数型言語ではよく「関数と関数を引き取って、合成した関数を返す関数」みたいなのが使われるんだけど、関数と関数の合成って、それ合成された関数がもともと引数として与えられていた関数憶えてないと無理やん? 自分自身の構成部品憶えてられないわけだから。
クロージャあると憶えててくれるわけですよ。
そんな感じで高階関数を実用的なレベルで使うのには大体必須と言う。
関数型言語はDSLを作りまくる言語みたいに書いたけど、モナドはちょっと複雑なDSLを簡単に作らせてくれる仕組みだと思っとけば良い。
まず純粋の定義だけど「全ての関数は同じ引数を与えられた際、必ず同じ値を返す」ってことで、これがいわゆる副作用がないって状態だ。
で、これって逆に言えば「プログラム内である関数に対して、絶対に同じ引数を与えさえしなければ、その関数がどんな値を返したところで、事実上純粋だと言えてしまう」ってことでもある。
本末転倒感があるんだけど、HaskellではIOモナドという仕組みと特別なmain関数を使って「呼び出すたびに絶対に違う引数を自動的に関数に与えてくれる仕組み」を実現していて、こいつを使って入出力する。
うん……凄い本末転倒。ちなみにこの自動的に与えられる引数はRealWorldって名前がついていて、要は「刻一刻と変わり続け絶対に同じ状況にならない現実世界の状態を引数に取っちまっているようなもんだからしょうがないだろ?」的な感じ。
第1章 並行プログラミングとGHC (上田和紀)1.1 はじめに1.2ターゲットを明確にしよう1.3 はじめが大切1.4GHCが与える並行計算の枠組み1.4.1GHCにおける計算とは,外界との情報のやりとり(通信)である1.4.2計算を行う主体は,互いに,および外界と通信し合うプロセスの集まりである1.4.3プロセスは,停止するとは限らない1.4.4プロセスは,開いた系(open system)をモデル化する1.4.5情報とは変数と値との結付き(結合)のことである1.4.6プロセスは,結合の観測と生成を行う1.4.7プロセスは,書換え規則を用いて定義する1.4.8 通信は,プロセス間の共有変数を用いて行う1.4.9外貨も,プロセスとしてモデル化される1.4.10 通信は,非同期的である1.4.11プロセスのふるまいは,非決定的でありうる1.5 もう少し具体的なパラダイム1.5.1ストリームと双方向通信1.5.2 履歴のあるオブジェクトの表現1.5.3データ駆動計算と要求駆動計算1.5.4 モジュラリティと差分プログラミング1.5.5プロセスによるデータ表現1.6歴史的背景と文献案内1.7 並行プログラミングと効率1.8 まとめ第2章 様相論理とテンポラル・プログラミング (桜川貴司)2.1 はじめに2.2 様相論理2.3 時制論理2.4 多世界モデル2.5 到達可能性と局所性2.6 純論理プログラミングへ向けて2.7 TemporalProlog2.8 RACCO2.9 実現2.10 まとめと参考文献案内第3章レコード・プログラミング (横田一正)3.1 はじめに3.2レコードと述語の表現3.3レコード構造とφ-項3.3.1 φ-項の定義3.3.2 型の半順序と束3.3.3KBLとLOGIN3.4 応用――データベースの視点から3.4.1演繹データベース3.4.2レコード・プログラミングとデータベース3.4.3 いくつかの例3.5 まとめ3.6 文献案内第4章抽象データ型とOBJ2 (二木厚吉・中川 中)4.1 はじめに4.2抽象データ型と代数型言語4.2.1抽象データ型4.2.2代数型言語4.2.3 始代数4.2.4 項代数4.2.5 項書換えシステム4.3 OBJ24.3.1 OBJ2の基本構造4.3.2モジュールの参照方法4.3.3 混置関数記号4.3.4モジュールのパラメータ化4.3.5パラメータ化機構による高階関数の記述4.3.6 順序ソート4.3.7属性つきパターンマッチング4.3.8 評価戦略の指定4.3.9モジュール表現4.4 おわりに第5章プログラム代数とFP (富樫 敦)5.1 はじめに5.2プログラミング・システム FP5.2.1オブジェクト5.2.2 基本関数5.2.3プログラム構成子5.2.4関数定義5.2.5FPのプログラミング・スタイル5.3プログラム代数5.3.1プログラム代数則5.3.2代数則の証明5.3.3代数則とプログラム5.4ラムダ計算の拡張5.4.1ラムダ式の拡張5.4.2拡張されたラムダ計算の簡約規則5.4.3 そのほかのリスト操作用演算子5.4.4 相互再帰的定義式5.4.5ストリーム(無限リスト)処理5.5FPプログラムの翻訳5.5.1オブジェクトの翻訳5.5.2 基本関数の翻訳5.5.3プログラム構成子の翻訳5.5.4 簡約規則を用いた代数則の検証5.6 おわりに第6章カテゴリカル・プログラミング (横内寛文)6.1 はじめに6.2 値からモルフィズムへ6.3カテゴリカル・コンビネータ6.3.1ラムダ計算の意味論6.3.2 モルフィズムによる意味論6.3.3カテゴリカル・コンビネータ理論CCL6.4関数型プログラミングへの応用6.4.1関数型プログラミング言語ML/O6.4.2 CCLの拡張6.4.3 CCLに基づいた処理系6.4.4公理系に基づいた最適化6.5 まとめ第7章最大公約数――普遍代数,多項式イデアル,自動証明におけるユークリッドの互除法 (外山芳人)7.1 はじめに7.2 完備化アルゴリズム7.2.1 グラス置換えパズル7.2.2 リダクションシステム7.2.3 完備なシステム7.2.4 完備化7.2.5パズルの答7.3普遍代数における完備化アルゴリズム7.3.1群論の語の問題7.3.2 群の公理の完備化7.3.3Knuth-Bendix完備化アルゴリズム7.4多項式イデアル理論における完備化アルゴリズム7.4.1ユークリッドの互除法7.4.2多項式イデアル7.4.3 Buchbergerアルゴリズム7.5 一階述語論理における完備化アルゴリズム7.5.1 レゾリューション法7.5.2 Hsiangのアイデア7.6 おわりに第8章 構成的プログラミング (林 晋)8.1 構成的プログラミング?8.2 型付きラムダ計算8.3論理としての型付きラムダ計算8.4 構成的プログラミングとは8.5 構成的プログラミングにおける再帰呼び出し8.6 おわりに:構成的プログラミングに未来はあるか?第9章メタプログラミングとリフレクション (田中二郎)9.1 はじめに9.2計算システム9.2.1因果結合システム9.2.2メタシステム9.2.3リフレクティブシステム9.3 3-Lisp9.4リフレクティブタワー9.5GHCにおけるリフレクション9.5.1 並列論理型言語GHC9.5.2GHCの言語仕様9.5.3GHCのメタインタプリタ9.5.4リフレクティブ述語のインプリメント9.6 まとめ
第1章 新しいプログラミング・パラダイムをめぐって (井田哲雄)1.1 はじめに1.2プログラミング・パラダイムの形成1.3プログラミング・パラダイムの展開1.4パラダイムと作法と構造化プログラミング1.5構造化プログラミングを超えて1.6関数型プログラミング,論理型プログラミング,対象指向プログラミング1.7 新しいプログラミング・パラダイム1.8 まとめ第2章ラムダ計算と高階プログラミング (横内寛文)2.1 はじめに2.2ラムダ計算2.3 最左戦略2.4コンビネータによる計算2.5 まとめ第3章マルセイユProlog,Prolog Ⅱ,Prolog Ⅲ3.1 はじめに3.2 準備3.2.1 述語3.2.2 項3.2.3 項の単一化3.2.4 節およびHorn節3.2.5論理式の意味3.2.6論理的帰結と導出3.3マルセイユProlog3.3.1Prologの記法3.3.2Prologの計算規則3.3.3Prologプログラムの例3.3.4カット・オペレータ3.3.5DEC-10Prologとの相違3.4Prolog Ⅱ3.4.1 difオペレータ3.4.2 freeze3.4.3ループ構造3.4.4Prolog Ⅱのインプリメンテーション3.5Prolog Ⅲ3.5.1 制約の枠組3.5.2Prolog Ⅲのプログラム例3.5.3 束縛の領域と制約系3.5.4Prolog Ⅲのインプリメンテーション3.6 まとめ第4章 制約論理型プログラム (相場 亮)4.1 はじめに4.2 制約プログラミング4.3 制約の分類4.4プログラムの実行4.5 制約の評価4.6 まとめ第5章オブジェクト指向 (柴山悦哉)5.1 はじめに5.2 モジュラリティと抽象化5.2.1抽象化5.2.2手続き抽象5.2.3データ抽象5.2.4オブジェクトによる抽象化5.2.5 並列オブジェクトによる抽象化5.3 共有5.3.1 多相型5.3.2継承5.3.3 多重継承5.3.4 Self5.3.5 動的束縛の意義5.4 対話性5.4.1クラスの再定義5.4.2 表示機能の一体化5.5オブジェクト指向の弱点5.6 まとめ第6章型推論とML (横田一正)6.1 はじめに6.2LCFの超言語からMLへ6.3プログラミング言語と型6.4MLの表現と型宣言6.5MLの型推論6.6LCFへの応用6.7 まとめ第7章Miranda (加藤和彦)7.1 はじめに7.2Mirandaの概観7.2.1 等式による定義7.2.2 基本データ型と基本演算子7.2.3 ガード付き等式とスコープ・ルール7.2.4高階関数とカリー化7.2.5パターン・マッチング7.2.6 ノンストリクト性と遅延評価7.2.7ドット式とZF式7.3 型7.3.1 強い型付けと静的な型付け7.3.2 多相型7.3.3 型類義7.3.4代数データ型7.3.5抽象データ型7.4処理系7.5 まとめ7.6 文献の紹介第8章 項書換えシステムと完備化手続き (大須賀昭彦)8.1 はじめに8.2 項書換えシステム8.3 TRSの停止性8.3.1意味順序8.3.2 構文順序8.4 TRSの合流性8.4.1 完備なTRS8.4.2危険対8.4.3危険対を用いたTRSの合流性判定8.5Knuth-Bendixの完備化手続き8.6KBの応用8.6.1帰納的な定理証明への応用8.6.2 等号論理の定理証明への応用8.7 まとめ第9章 等式プログラミングから融合型プログラミングへ (富樫 敦)9.1 はじめに9.2 等式プログラミング9.2.1 等式プログラム9.2.2 代表的な等式プログラム9.2.3プログラミング技法9.2.4 正則プログラムと正規化戦略9.3 条件付き等式プログラム9.3.1 条件付き書換え規則9.3.2 条件の種類9.3.3 利点と問題点9.4 融合型プログラミング9.4.1 AMLOGシステム9.4.2 向付き等式9.4.3 実行戦略の変更9.4.4 代入操作9.4.5 合流するプログラムへの変換9.5 まとめ
いくつか考えてみた
(問1)高階関数と再帰関数を必ず使って数値を要素とするリストの要素の総和を求める関数を書け。ただし高階関数を使うという要件と再帰関数を使うという要件は同じ関数で満たしてもよい。
(問2)二つの引数をとり二つのうち大きいほうを返す関数と高階関数、再帰関数をつかって数値のリストの最大値を求める関数を書け。ただし高階関数を使うという要件と再帰関数を使うという要件は同じ関数で満たしてもよい。
というのは簡単すぎるか?簡単すぎるなら
(問3)高階関数と再帰関数を必ず使ってある数値に5を足し、10かけて2で割った数を求める関数を書け。ただし高階関数を使うという要件と再帰関数を使うという要件は同じ関数で満たしてもよい。
こっちの方がいいかな。でもトリッキーすぎる気もする。
一応問題を出したので、SchemeとPythonで自分で想定している答えを書いておいた。はてなではSchemeが人気のようなので、あまり知らなかったけど関数言語ではSchemeで書いておいた。Pythonで書くのはSchemeだけだとわかりにくいので、なにかスクリプト言語で書いておこうと思ったから。Rubyの方が人気なので、はじめはRubyで書こうと思ったけど挫折した。だれかRubyで書いてくれないかな・・・。コードオブジェクトってなによ。というか関数はオブジェクトなのに引数にできないの?なんで?(以下疑問と愚痴の嵐なので略)Perlは古株が多くてユーザー数も多そうだけど、・・・その・・・無理です・・・。あの言語仕様はやる気がしない。ぶっちゃけ理解できない。Pythonを知らないひとは多そうだけど、知らなくてもSchemeよりは感じは掴めると思うのでPythonでも書いておくことにした。
http://anond.hatelabo.jp/20071110215936
http://anond.hatelabo.jp/20071110220132
これで大部分のひとがこの問題に興味をもたなくて解答するひとがいなくても、興味を持ったひとは安心だね!
追記:
問3で次のは無しとしておきたい。
(define continuous-apply (lambda (lst obj) (cond ((null? lst) obj) (else (continuous-apply (cdr lst) ((car lst) obj))))))(define plus5 (lambda (num) (+ num 5)))(define times10 (lambda (num) (* num 10)))(define divide2 (lambda (num) (/ num 2)))(define plus5-times10-divide2 (lambda (num) (continuous-apply (list plus5 times10 divide2) num)))(plus5-times10-divide2 2)
def continuousApply(lst, obj): if lst: return continuousApply(lst[1:], lst[0](obj)) else: return objdef plus5(num): return num + 5def times10(num): return num * 10def divide2(num): return num / 2def plus5_times10_divide2(num): return continuousApply([plus5, times10, divide2], 2)plus5_times10_divide2(2)
あくまで自分でこう答えるという話。
(問1)
(define fold-left (lambda (func obj lst) (cond ((null? lst) obj) (else (fold-left func (func obj (car lst)) (cdr lst))))))(define my-sum (lambda (lst) (fold-left + (car lst) (cdr lst))))
・例
(my-sum '(1 2 3 4 5 6 7 8 9 10))
(問2)
(define fold-left (lambda (func obj lst) (cond ((null? lst) obj) (else (fold-left func (func obj (car lst)) (cdr lst))))))(define large (lambda (x y) (cond ((>= x y) x) (else y))))(define my-max (lambda (lst) (fold-left large (car lst) (cdr lst))))
・例
(my-max '(58 90 1 2 4 3 100))
(問3)
(define fold-right (lambda (func lst obj) (cond ((null? lst) obj) (else (func (car lst) (fold-right func (cdr lst) obj))))))(define my-apply (lambda (func obj) (func obj)))(define plus5 (lambda (num) (+ num 5)))(define times10 (lambda (num) (* num 10)))(define divide2 (lambda (num) (/ num 2)))(define plus5-times10-divide2 (lambda (num) (let ((lst (list plus5 times10 divide2))) (fold-right my-apply (reverse lst) num))))
・例
(plus5-times10-divide2 5)
全部畳み込み関数を使っているのは、はじめ使い道がないと思ってたのにかなり使い道があることがわかったので、それを示したかったから。あとmap関数あたりはほかの言語でもあるから、すぐに思いつくだろうし。
というか最後のやつは手続きを抽象化することでリストの形で扱えるようにしているから、関数プログラミングでは重要だと思う。関数プログラミングの肝は計算によって手続きを含めたすべて表すことができることだと思っている。その例だと思うんだけどね。例えばSchemeなら上記の答えを応用して、似たような「手続き」を生み出す関数を作ることができる。
(definemake-proceduce (lambda (fst .rest) (let ((lst (consfstrest))) (lambda (num) (fold-right my-apply (reverse lst) num)))))
これを使うと次のようにできる。
(define divide2-plus5-times10 (make-proceduce divide2 plus5 times10))(divide2-plus5-times10 2)(define divide2-times10-plus5 (make-proceduce divide2 times10 plus5))(divide2-times10-plus5 2)
関数合成がつかえるならそっちのほうが楽だけど、リストという形で「手続き」をつくり出していることがわかるだろうか?手続きをリストで操作できるのだ。こういうのが関数プログラミングの肝だと勝手に思っている。
こうやってくると型推論や多相型の重要性もわかると思うんだよ。上記のようなことはPythonでもできる。でも高階関数はつかいすぎるとわかりにくい。どっかにバグが入ってくるかもしれない。それを機械的に防ぐのが型推論。型という観点から型推論でおかしいところを探し出してくれる。それならC言語でもいいのではないかという人もいるかもしれない。だがC言語は融通が利かない。例えばapply関数にしても引数の型が数値なら数値、文字なら文字と決まっている必要がある。だから数値に向けにapply関数を作っても文字には使えない。こうした型のデメリットをなくす一方、そのメリットを享受するためにあるのが多相型。これによってapply関数やmap関数を一般的に作ることができ、型のメリットを享受しながらデメリットをなくすことができる。このように関数で手続きなんかを抽象化するときに型推論や多相型があると便利なのだ。
http://anond.hatelabo.jp/20071021143442
その理由は知らないが、なければ作ればいいじゃないか。
class MyString(str):def length(self): return len(self)
というクラスを作って
string = MyString("Hello world")printstring.count("o"),string.length()
とRubyライクにやれば
2 11
とでるよ。え、リストもlist.length()が使いたいって?それも簡単。
class MyList(list):def length(self): return len(self)l = MyList([1, 2, 3, 4, 5, 6])l.length()
6
きちんと他のメソッドも使えるよ。
l[1:]
[2, 3, 4, 5, 6]
l.reverse()l
[6, 5, 4, 3, 2, 1]
ね。簡単でしょ。
Pythonは仕組みが統一されているものが多いので、いじりやすいのですよ。上の例のやつは組み込みのクラスオブジェクトとユーザー定義のクラスオブジェクトがおおむね統一されているからこそ簡単にできる。他にも関数なんかもほかのオブジェクトと同じオブジェクトなので、高階関数なんてもの簡単に作ることができて関数プログラミングぽくできる。例えば今はなきapply関数なんかは
def myApply(func, *args): return func.__call__(*args)
と定義できる。実際に
def sumUpThree(num1, num2, num3): return num1 + num2 + num3
でためしてみる。
myApply(sumUpThree, 1, 2, 3)
結果はちゃんと
6
とでる。将来廃止されそうなmap関数も簡単に定義できる。他にも複数の引数をもつ関数の部分適用のようなことを行う関数も次のように簡単に定義できる。
def partial(func, *oldArgs):def wrapper(*newArgs): return func.__call__(*(oldArgs + newArgs)) return wrapper
sum_1 = partial(sumUpThree, 1)sum_1(2, 3)
6
sum_1_5 = partial(sum_1, 5)sum_1_5(9)
15
sum_10_20 = partial(sumUpThree, 10, 20)sum_10_20(30)
60
こういう風に高階関数が簡単にできるのは関数がオブジェクトで関数の実行とはメソッドの呼び出しにすぎないからだ。以上のように組み込みオブジェクトとユーザー定義オブジェクトの差があまりないことや関数もオブジェクトであることに見られるようにPythonは仕組みが統一されていてシンプルだ。そのためひとつのことがわかれば他のこともわかることが多いし、簡単にいじることもできる。
だからなければpythonをいじればいいと思うよ。
最後にラムダ式信者のためにpartialをラムダ式を使って書いておく。
def partial(func, *oldArgs): return lambda *newArgs:func.__call__(*(oldArgs + newArgs))
これから就職活動するバカはいないだろうけど、そういう人もいるだろうから少し書いておこう。
どちらかというと、アンチMS派なUnix技術者がWindowsだけの世界で仕事をする辛さを。
Unix技術者は、業務実績にSolaris/AIX/Linuxって書いてあってもちゃんと質問しろ。Windowsの仕事は無いですよね?って。
僕が食べるために職を手にしているこのIT業界というのは、バッドノウハウとMicroSoftとExcelで出来ている。
その為、僕が手にしたUnixの知識は、特定の仕事以外でしか役に立たないし、使わない。
viだろうが、TeXだろうが、Xの知識よりも、MFCとVBAのちょっとした知識のあるヤツが上にみられる。
ExcelとWindowsの知識があればそれだけで仕事になるからだ。
いいか、viやTeX、Xなんて捨てちまえ、Excelがあればそれでいいのだ。
MSでは、ActiveXを使ってCOMを操作し、クライアントのレジストリを操作し、IE単体でできないことをやってしまうヤツがハッカーと思われている。
VBAマクロで作ったなんちゃってツールを3時間で作れるほうが、
perlやruby/pythonで、より少ない時間で作ったツールよりも凄く思われてしまう。
そして、それができるヤツの方が、Unix技術者よりもよりハッカーであり、技術力があると思われている。
ブラウザを例にしたが、
javascriptでalert/confirmを出すよりも、vbscriptでMsgBoxの方が多くのことができるから、
javascriptでNumberの計算よりも、vbscriptでDecimalを使った方が倍密度の計算ができるから、
vbscriptを駆使できるヤツは、凄く重宝される。
いいか、javascriptで汎用的に書くのなんてナンセンスだ。javascriptなんて捨てちまえ、覚えるのはJScript実装(WSH)だ。
この業界、何が不満になるかというと、
MSの、もっというとWindowsのことしか知らないヤツが多すぎるということ。
そういうヤツらは、Windowsだったらこんなこともできるのに、なぜUnix/Linuxだとこんなこともできないのか。と言う
そういうヤツらは、Windowsの未修正バグの合間を縫いながら中途半端な実装しかしない。
だって、中途半端(もしくは大雑把)な実装で動いているものの中で動くから。それ以上に実装しようとしてもできないのだ。
いいか、win32のメッセージングの仕組を覚えるんだ。無理矢理send_keyみたいなコードを書けるようにしろ。
コマンドを連結するよりも、結果に近いコードを書くんだ。線形になろうがヤツらは気にしないだろう。
何故か。
それは、.NETで作ればお客さんの要望が実現でき、Excelと連携できるからだ。
ヤツらは、C/Sの世界でこそ役に立つ技術者だが、Webの世界に連れてきてはならない。すぐに実装がIEだけになる。
ヤツらにLLを覚えさせるのは無理だ。
クロージャなんて知らないし、高階関数やカリーなんてコードを教えてみろ。後から辛くなるのは自分だ。
ヤツらにはPHPを教えておけ、それだけで満足する。すごいヤツになった気にさせれる。
バッドノウハウ慣れしているヤツらはそれを使ってコードを書いてもらえ、rubyで書かせるよりも修正が20倍楽だ。
いいか、まとめるぞ。
今まで一生懸命Unixを勉強してきたのは無駄だ。いますぐ忘れるんだ。
Excelを今から覚えろ。VBAを覚えろ。そしてMSの動きを身に着けるんだ。
Windowsでは単位がFormだ。それが標準出力と標準入力と思え。ときどきSheetとかWorkbookになるぞ。
ストリームやファイル操作には気をつけろ。Unixの気分でいると思わぬところで抜けが出るぞ。
IRCは使うな。Jabberを使うな。メッセンジャーを使え。移行のお薦めはGaimだ。Windows版がある。
viの使用頻度を減らせ、変なコマンドを身に着ける前に、秀丸マクロを書けるようにしろ、Notepadのショートカットを覚えとけ。
BindとかApache(Httpd)の知識はいらない。IISだ。ActiveDirectoryだ。
文字コードはCp943cを何がなんでも押せ。Shift_JISっていう大雑把な伝えかたはダメだ。絶対cp943cにしろ。UTF8/UTF7との格闘で身も心もぼろぼろになるぞ。
汎用性なんて無いんだ。Windowsというプラットフォームがあれば。
ああ、心が渇いていく。