「高階関数」を含む日記 RSS

はてなキーワード: 高階関数とは

2022-03-05

プログラマ必要なのはググる力」"ではありません"

プログラミング必要なのはググる力だ」などとまことしやかに言われます。が、これは嘘なので、プログラミング初心者は(中級者以上も)真に受けないで下さい。そして、プログラミング教育に携わる人は、こういう有害な嘘を広めるのはやめて下さい。

なお、ここでいう「プログラマ」とはプログラミング仕事にする人、または作成したプログラムを公開する人を指しています純粋趣味プログラミングをしており、ソースコードソフトウェアも公開するつもりの無い人は、どんな方法プログラミングをしようと自由です。

プログラマ必要な力

プログラマに(プログラマに限らず)必要なのは自身の専門分野に関する基礎的かつ体系的な知識です。それらが不足していては、「ググる」ことさえままなりません。英語で喩えれば、時制や不規則動詞という概念を知らずに辞書を引いて、「I saw him yesterday. 」の「saw」をのこぎりのことだと思い込むようなものです。要するに、調べたい事項が何に関するものなのかを理解していなければ、調べようがないのです。

それでは、プログラミング初心者にとって必要な基礎知識は具体的にどのようなものでしょうか。

まず当然ですが、自分が使っているプログラミング言語フレームワーク機能は一通り知っている必要があります組み込みデータ型や制御構文はもちろん知らなければいけません。高階関数クラス、非同期処理等の発展的な機能も知る必要があります言語だけではなく、パッケージマネージャタスクランナー単体テストツール等の周辺ツール理解必要です。また、「コードコンプリート」とか「Effective ○○」のような書籍に書いてあるような設計コーディングベストプラクティスも知らなければいけません。要するに、現代プログラミングの「常識」は全て知っている必要があります

そもそも「そういう機能存在する」と認識して初めて「調べる」ことができるのです。列挙型という機能存在を知らずに「Javaで列挙型はどう書くのだろう」と調べることはできません。非同期処理の存在を知らずに、「JavaScriptで非同期処理はどう書くのだろう」と調べることはできません。

初心者は何から学ぶべきか

では、そのような一通りの知識を身に着けるためには、どのようなリソースから学ぶべきでしょうか。

結論から言えば、以下のような文献で学ぶべきでしょう。

逆に、WikipediaQiita等の個人趣味で書いた記事プログラミングスクール記事プログラミングスクール家庭教師etc主体に学ぶのはやめるべきでしょう。

もちろん、特定話題について調べる過程で、非公式情報に行き着くことはあるでしょうが、そこで使用されているライブラリ等の仕様については、必ず公式ドキュメントで裏を取るべきです。

時々、こういった正式ドキュメントを読むことが、初心者にはハードルが高いと言う人がいますしかし、冒頭で述べたようなプログラミング仕事にしようとしている人達が、こういうことができないのはおかしいです。

実際、公式ドキュメントを読むことはそれほど難しいことではありません。有名な言語ライブラリ等のドキュメントであれば、高校程度の数学英語とある程度のコンピュータ操作経験があれば、理解できるように書かれています。その程度の素養も無いのにプログラマ特に職業プログラマ)になろうとすることが、そもそもおかしいのです。運動が苦手なのにプロスポーツ選手になろうとするようなものです。

2021-07-12

いい加減「プログラミング理解できない人はいる」という事実を認め

てほしい。

プログラミング理解できない人はいます。いい加減この事実を認めて下さい。

こういう話になると、やれ「教え方が悪い」だとか、やれ「順序立てて学べば誰でも理解できる」などという輩が出てきますが、それは事実に反します。

まず、プログラミングは手順さえ覚えれば誰でもできるようになると言うものではありません。プログラミング理解するには、一定レベル論理的思考能力を要します。それが身に付いていない人には無理です。また、どんなレベルの人でも、プログラミングで分からないことは出てきますプログラミングができる人は、そういう時に、

といったことをして解決する力があります。そういう試行錯誤をしない人や、複雑だったり抽象的な概念を突き詰めて考えることをしない人に、プログラミング理解するのは不可能です。

たとえば、再帰関数が分からないとしましょう。具体的に何が分からないのかは人によって異なります。たとえば、

など。これらを解決するには、自分で仕組みを突き詰めて考えたり、コードを書いてデバッグしてみたり、調べたり人に聴いたりするしかありません。講師が気の聞いた喩え話などをすれば、たちまち疑問が氷解するなどということはあり得ません。

また、一口に「プログラミング理解する」と言っても、そのレベルは様々です。

  1. 代入や四則演算などが理解できる
  2. 条件分岐や繰り返しなどの制御構文が理解できる
  3. 関数クラスなどのモジュール機構理解できる
  4. 高階関数や非同期処理などが理解できる
  5. 計算量を見積もることができ、効率の良いコードが書ける
  6. ソフトウェア設計理解し、保守やすプログラムが書ける
  7. バージョン管理等の各種自動化ツールOSネットワークデータベース等のプログラミング言語以外の技術理解している

最初の2〜3程度が「自分の思うプログラミングの全て」な人が、軽々しく「プログラミングは誰でも理解できる」などと思わないでいただきたいのです。それは実用上は全然足りていません。サンプルコードをググりながら、やっとこさVBA複数エクセルファイルを集計できる程度の人が「プログラミングできる」気になっていては困るのです。

上記の大部分は、自分プログラム他人に見せるつもりのある人なら十分に習得しておく必要があります。ましてや、プログラミングで飯食おうと言う人間が、FizzBuzzに毛の生えたようなコードを読み書きするのに精一杯で、効率保守性に気を配れないのは論外です。

上記特に後半に書いたようなことは、誰にでもできることではありません。ちょっとしたコツや方針を守れば機械的にこなせるというものではなく、技術力の高い人でも熟考を要することです。彼らは、そうした高度なことを正しく考える力があるから技術力が高いのです。そういう力は、誰かに用意してもらったカリキュラム受動的にこなすだけではまず身に付きません。

2021-06-17

経験から1ヶ月でWeb企業就職する勉強法

取り上げた技術は、本格的な開発でも役に立つもので、最も学習コストが低いものを選んだ。

重要度が低いものは載せていない。たとえばHTMLCSSなんてググりながら書けば全く問題ない。Bootstrapなどのフレームワークも全くやる必要はなく、仮に就職先で使っていたら覚えればいい。

逆に言えば以下に挙げる技術は、そもそも概念自体プログラミングにとって普遍的ものであり、(基礎的な部分を)調べながら使うようではエンジニア失格ということ。

基本的現在では、バックエンドフロントエンド運用保守全てができないエンジニア価値は無い。

以下に挙げた技術(①⑤⑥は他の言語フレームワーク代替可能)が身に付いていなければまともな企業就職することは難しい(もちろん、下らない業務システム下請けで作ってる底辺企業には入れるだろうが)。

経験者でも、これらができない/わからないのは、相当恥ずかしいことだと思った方がいい。

特定言語フレームワークの書き方を知っていること自体意味は無い。

重要なのは、他の言語フレームワークにも共通する基礎を理解すること・保守性やセキュリティなどの品質を高める使い方ができること。

PythonJavaScriptマスターする

この2つは習得が容易だし、今覚えておけば向こう10年腐ることはないだろう。

プログラミング言語完璧理解する必要がある。

基本的な構文や、よく使う標準ライブラリは勿論、高階関数クラス・非同期処理等の発展的な機能も知り尽くしていなければならない。

言語のみではなく、パッケージ管理単体テストタスクランナー等の周辺ツールの使い方も熟知している必要がある。

また、「リーダブルコード」や「コードコンプリート」に書いてあるような良い作法も身に付ける必要がある。


Gitの基本操作を覚える

Gitを使えないのはプログラマーとして論外。細かい機能は調べればよいが、

等の基本的フローは必ずできなければならない。


Linuxの基本操作を覚える

多くの場合、本番環境テスト環境Linuxサーバーであるから、以下のような基本的概念と使い方を知っておく必要がある。


Dockerの基本操作を覚える

環境構築、CIデプロイなどは、現在コンテナを使って行うことが当たり前になっている。

これも細かいことをすべて覚える必要はないが、Dockerfileの書き方や、docker-composeの使い方などは知っておかなければいけない。


⑤ Flaskを覚える

Flaskは、数あるWebフレームワークの中で最も簡単。本当に呆れるほど簡単で、Pythonさえ書ければすぐにアプリを作れる。

フレームワークを覚えること自体重要なのではなく、Web開発の基本を習得することが重要HTTPルーティングデータベースSQL認証セッション管理などは当然すべて覚える。

データベースは、就職したらMySQLPostgreSQLなどを使うことが多いかも知れないが、今はPythonの標準ライブラリにあるSQLite3を使えば十分。

作ったアプリを公開したければ、「Heroku」などにデプロイするのが良いだろう。

追記 2021/06/17 14:07

ブコメで指摘をいただきました。HerokuではSQLite3は使用できないようです。公式ドキュメントに従ってPostgreSQL使用して下さい。

SQLite3はファイルデータを持てる簡易DBなんだけど、Herokuデプロイしてもストレージ的な使い方はできないから、結局PostgreSQLを使う必要あるから注意してね。(DAOを丸ごと書き換える羽目になる)

参考: https://devcenter.heroku.com/ja/articles/sqlite3

ありがとうございます

Vue.jsを覚える

今の時代フロントエンドフレームワークなしで作るのはただのバカ

2021年現在実用的なフロントエンドフレームワークはReactとVueしかない。Vueの方が少し簡単なのでこちらを選んだが、JavaScriptをしっかり理解しているなら大差は無い。

フロントエンドには膨大なパッケージ群があって全部覚えるのは大変だが、とりあえずまずはVue完璧に使えればいい。Webpackの設定などは既存のものを流用すればいい。



基本的アルゴリズムを学ぶ

アルゴリズムは全てのコンピュータ技術の基礎であり、絶対に知っていなければならない。

高速フーリエ変換のような高度な数学必要ないが、クイックソート木構造のような基本的アルゴリズムは当然、その性質を知っていなければならない。

それらは言語組み込み関数や標準ライブラリでも使われており、理解していなければ、それらの機能を正しく使うことができない。

また、プログラムを読み書きする際には、そのコード計算量を見積もれなければならない。

セキュリティを学ぶ

セキュリティは言うまでもなく学ばなければならない。

有名な脆弱性攻撃手法XSSSQLインジェクション・CSRFなど)が何だか理解していて、その対策実装できなければならない。

各種暗号化技術署名などについても、実装の詳細は知らなくていいが、共通鍵暗号や公開鍵暗号などの特性理解する必要がある。

認証パスワード管理などを実装する際は、当然ベストプラクティスに従わなければならない。

2020-11-03

anond:20201030201448

高階関数どころかループといえばFORしかなく

変数スコープなんてものさえなかった時代

こう書くしかなかったんやろな……という悲しみはある

2020-10-30

お願いだからセンスの無い人はプログラマにならないで下さい

プログラミングセンスです。センスの無い人がプログラマになると、他のすべての人に迷惑がかかります。だからセンスの無い人は絶対プログラマにならないで下さい。

プログラミングセンスが無い人や、プログラミングをやったことの無い人は、知識を得たり経験を積んだりすれば、誰でも「良いプログラマ」になれると思っているようですが、無理です。

というのも、センスの無いプログラマ問題は、知識経験の不足ではないからです。センスの無いプログラマの救いようの無い問題は「頭がおかしいこと」なのです。

題材は何でもいいのですが、具体的なコードを見た方がイメージがつきやすいと思いますので、とりあえず以下の問題を考えます

問題

住民リストが与えられるので、背の低い順に男女ペアにしたリストを作って下さい。ただし、男女の数は同数であるします。

コード

ふつうの人は、難しく考えずに以下のようなコードを書きます

const makePair = (persons) => {
  const males = persons.filter(person => person.sex === MALE)
  const females = persons.filter(person => person.sex === FEMALE)
  const compareHeight = (a, b) => a.height - b.height
  males.sort(compareHeight)
  females.sort(compareHeight)
  return males.map((male, idx) => [male, females[idx]]) // 男女の数は同数
}

この例はJavaScriptなので高階関数を使っていますが、仮にそういう機能が無かったとしても、

というコード構成は大きく変わらないでしょう。

一方、センスの無いゴミプログラマは、以下のような名状しがたきコードを書いてきます

function pair(psns) {
  var i = -1;
  var cnt = 0;
  var flg = psns[0] && 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だと上手くいかない(by XXXX)。
      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から書き直せますが、実際のプロダクトでは、無数の副作用を起こす数千行のコード迷路を彼の脳内フォーマットデータが通るわけです。もちろん、テストコードなんてありません。

まり、指摘をしても絶対に直らないのです。いくら言語の優れた機能ベストプラクティスを紹介しても、馬の耳に念仏。それらの利点を理解できるだけの脳みそが足りていないのです。

どうして、同じ処理を実装するのに、ここまでの違いが生じるのでしょうか。

これは、プログラミング技術問題ではありません。既に述べた通り、ふつうの人なら、特定機能の有無とか知識の程度にかかわらず、ふつうコードを書くのです。なぜなら、ふつうの人にはそちらの方が楽だからです。つまり、前者のコード別に何か卓越した技術を身につけた結果書けるようになるものではなく、まともな感覚さえ持っていれば、プログラミング初心者にとっても前者のコードの方が書きやすいのです。

まり後者のようなコードを書いてくる奴というのは、現実世界の捉え方が常人とは著しくずれているのです。要するに、「頭がおかしい」のです。この病気はもう直りません。だからセンスの無い人は絶対プログラマにはならないで下さい。

2020-02-27

anond:20200227004129

何か関数型嫌いみたいだが

高階関数

とか

Lambda

とか

イミュータブル型

とか、最初関数型言語で使われ始めた機能が、Kotlinなんかの後発言語に取り入れられて便利に使われるっていう流れがあるんやで

勉強無駄にはならんのよ

2018-04-03

haskell勉強

高階関数遅延評価とか参照透過性とか結構面白い概念でやってて楽しいんだけど

デフォルト遅延評価だったり参照透過性だから実行中に何しても値変えられないとかやっぱ頭おかしいわ

でもこれ好き、癖になりそう

2017-04-07

http://anond.hatelabo.jp/20170407112743

意識低い企業研究者です。プログラミングはサブウエポン。だけど趣味でも勉強してる。

働き方改革のせいで早く帰れって言われて、酒のみながら今これを書いてる。

C言語とかC++・・・これで作らないといけないものが今の所ないし、これでお金を稼ぐのはハードルが高いし、

WindowsAPIを使って複雑なプログラムを作りたいわけじゃないのでwhileとかifとか基本的な構文だけ覚えるだけで満足。

組み込みプログラミングではC言語はいまだに現役。お金普通に稼げると思うよ!次代のCOBOLと化しそうで怖いとこはあるけど。

Java・・・使える人が多いからあえて今から学習しなくてもいいような気がする。

文字列の結合だけでもダメやり方と良いやり方があるらしくて、何かPHPのようにその言語特有セオリーみたいなのを覚えるのが面倒くさそうなので入門の時点で学習するのをやめた。

セオリーとかあるかもしんないけど速度とか気に揉むまえに書いて測れ。たいていは杞憂か、あるいはCPUパワーで殴れるから

Go・・・HTTP/2が使えるから学習してる。他の言語だとnghttp2をインストールしないといけないようなのでGo便利だと思ってる。

ライブラリ選択肢が多すぎるのでこういうのが作りたいってときにこれを使うのがいいよっていうのが知りたい。

GUI作るのにライブラリありすぎてどうやって選べばいいのかさっぱりわかんない。

Goデータベース扱うならこれを使え、だけどMySQLしか使わないならこれを使え、あっSQLiteならこっちのライブラリ使うと便利みたいなこういう情報が欲しい。

GoGUIつくるの?あんまり普通じゃない気がする。軽量プロセスうまみがそんなない(詳しい人に否定されそうだけど)

普通にC#(mono/.net)かwebアプリにするかで良くないか

ただ、言語をあれもこれも覚えるのって僕は意味があるのかなという思いもある。

20言語Hello World出来るより、1つの言語でいろんなアルゴリズムを知っている方がすごいと思う。

コミュ症がフランス語英語ドイツ語覚えても、使う機会がないとまったく価値がないと思う。

アルゴリズムは使うものだ書くものではない!!

広く浅く学習するより、狭く深くいきたいとおもうけど、paizaでCランクしか取れない。

twitterで有名な人てやっぱりSランクとか余裕なのかな、こういうのもいろんなプログラマーに聞いてみたい。

一応著名なプログラマーTwitterフォローしてるけど、ご飯の画像を載せてたり、若者の僕には通じない寒いギャク連発してたり、ロリっぽい画像RTしてたりと、twitterはメインの情報収集としては利用してない。

twitterやってるプログラマーって勉強会とかオフ会に参加してるようなリア充の人ばっかりなので、肩身が狭いか自分からリプは送ったりはしない。

ファンがたくさんいるのに最近ニコ生配信してくれないchokudai先生みたいに、アルゴリズムを学ぶのがいいのかな。

深さ優先探索とか理解できない。

コード写経しても覚えられないし、仕組みは理解したけど自力コードが書けない。

コードにする能力ってどうやって鍛えるのか知りたい。

アルゴリズムは使うものだ書くものではない!高階関数とかテンプレートプログラミングとかその辺勉強するといい。

あと計算制限時間内に終わるなら総当たりが最速で品質も高いぞ。

エディタサクラエディタからVimに変えた。

どうしてVimかというとプラグインが多いしIDEっぽくできるから

Vim使う一番の理由は補完が強いのが気に入ってるから

Vimってハードル高いイメージあったけど、入門記事がたくさんあるので助かっている。

NetBeansが重すぎるんだよ。補完ボックスが表示されるの遅すぎて警告メッセージが出た。補完ボックスが表示されるまで7秒ぐらい経過すると警告メッセージが表示されたと思う。

Vim知らない。Linux使うならVimemacs使えるだろみたいな雰囲気あるけど、GUIならgedit, CUIならnanoでいいよね。

パソコンスペックもどのくらいのものを用意したらいいのかわからない。

10年前のVistaが搭載されていた頃の家電量販店で一番安かったCeleron 1コア メモリ1GB グラボなしノートからプログラミングに向いてないのかもしれない。

VirtualBox上のubuntuMySQLコンパイルすると2時間20分ぐらいかかった記憶がある。

CPUが1コアなのでコンパイル中にそれ以外の作業なんて重くてできない。

スペックお金をかけることで時間節約ツール選択肢が増える

EclipseなどのIDEが支障なく使えるレベルスペックってどのくらいするんだろう。

ノートCore i3メモリ4GBにランクアップしたらいけるのかな。

他人がどんなスペックPCで何のツール使ってプログラミングしているか知りたい。

3年前のCore i7, SSD, 8GB。最近はもっぱらJupyter。

もっと早いPCが欲しいけど、年度末に買うのを忘れた。

Python・・・機械学習する上で避けて通れないけど、今のPCだと無理。

例題が豊富逆引き辞典みたいなサイトや本がほしい。

あと、クレジットカード持てないのでAWS上で機械学習するのだけは遠慮したい。

過大請求されるの怖いし、トラブルが起きた時に英語コミュニケーション出来ないから。

Pythonはいいぞ、機械学習だけじゃなく計算系はエクセルじゃなくてJupyter使う。でも周りはエクセルつかってる、勿体ない。

使ってないけど最先端研究では機械学習使って当たり前感があってそろそろヤバい

僕は中学生の頃、いじめにより心の余裕なんてなかったか勉強どころではなかったけどもっと英語勉強しておけばよかったと後悔している。

やっぱり子供の頃の生活環境って大事だなと思う。

今は英検3級に向けて勉強中。

APIドキュメント頑張って読もう。俺も頑張って読んでる。

何を学習したらいいのか本当にわかんない。

迷宮にいる感じ。

なんとなく、プログラミングじゃないほうがいい気がするなあ。

とりあえずバイトしてPC買わない?プログラミングバイトでもいいと思うよ。

働き方改革最前線からは以上です。

2016-02-26

関数型プログラミングのことは嫌いにならないでください!

高階関数はいいぞ!

lambdaはいいぞ!

ミュータブルはいいぞ!

homoiconicはいいぞ!

マクロはいいぞ!

Clojureはいいぞ!

2015-05-18

関数型言語が普及しない理由が分かった

関数型言語なんて、多くのプログラマにとって猫に小判、豚に真珠ということだ。

コミュニティ文化独自とか、学習コストが高いとか言われているが、それは本当の理由じゃない。

本当の理由は、オブジェクト指向言語すら使いこなせていないのに、関数型言語なんて必要ないという理由だ。

オブジェクト指向言語を使い倒していれば、同じ概念関数型言語ではずっと楽に実現できることにすぐに気づく。

逆にオブジェクト指向言語で無理して使っている概念(例えば高階関数など)がないと利点に全く気づけない。

普段余計な一手間を加えてでも、実現したい便利で強力な概念を、そもそも使っていないのでは、関数型言語を書く意味はない。

関数型言語でもオブジェクト指向言語でも、やることは変わらないとずっと思ってきたし、それなのになぜ関数型言語が普及しないのか、ずっと不思議だった。

しかし未熟なプログラマには無用長物だということだ。

2015-02-11

関数型とオブジェクト指向って……

毛の壁以降、色んなところであーだこーだ再定義言われてるけど、結局名前が悪いんだよなぁ。

どちらかというとオブジェクト指向の方が「何もかもサブルーチン(ただし値を覚えていてくれるおまけつき)」で、関数型の方が「何もかもが値(関数も)」なんだけど、まず名前からだと逆っぽく聞こえる。

加えて、この二つの概念が対立すると思われてしまうけれど、んなこたーないのはjavascript見れば分かる。何もかも値かつサブルーチン、でOK。

両立しにくいのは、オブジェクト概念高階関数概念ではなく、オブジェクト指向言語採用してきた型システムと、関数型言語採用してきた型システムだ。

まりC++やらJavaやらが採用してきたサブタイプ多相をベースにしたクラスによる型付けと、ML言語採用してきた代数データ型が噛み合わない。致命的に。

いやまぁScalaは頑張って統合したけど、コンパイル遅いわ書き方次第で型チェックが無限ループになるわで、色々と無茶しやがって感ある。

これからは「サブタイプ多相言語」と「代数データ言語」って分けて呼ぶべきなんじゃないか?

2014-09-14

「手に職」って詐欺みたいなもんなんだな

当方いわゆるwebプログラマ30代。大学卒業に失敗しているので学歴としては高卒年収は800万に届かない程度。webプログラマインターネット上で目立っている有名プログラマも多くて、彼らと自分を比べると絶望するくらいに自分スキルは低い。でも最低限の能力はあると思う(参考までに、 GitHub 上で一番starをもらっているリポジトリは 14 star というレベルの実力。150 star くらいあるリポジトリに PullRequest を送って取り込んでもらったことがあるという程度)。

で、このレベル人間が周りの年上プログラマを見てると、「なんだ、こいつらが食って行けるなら、俺は楽勝で食って行けるじゃん」って思うことが多い。「その辺のちょっとだけできる大学生のほうがよほどまともだぞ」みたいなコード書く人間がのうのうとプログラマとして食って行ってる。ほんとうにひどいやつらが多くて、一番笑えたのが「経験豊富だしどん欲に学習してきたのでどんな言語対応できます」って言ってた39歳の人間で、彼は「高階関数」という概念がまったく理解できなかった。「関数ポインタ引数で渡すみたいなもんですよ」って言ったら「関数ポインタとか実務で使うことないしwwwwwww」みたいに返されて絶句した。よく 2chプログラマ板で「if と for がわかればなんでも書けるし」みたいなこと言ってるやついるけど、「あーこういう人間がああい書き込みするんだな」って変に納得できた。

でもそのひとは会社からそこそこの金をもらってた。それ見て思ったんだけど、いくらひどいコードであっても、「とりあえず動くものが作れる」っていうのはスキルの一種であることには違いないんだな。正直絶対に一緒に働きたくないし、そいつが書いたコードは絶対にメンテしたくないけど、メンテナンス性がどれだけ大事かってことを理解している経営層っていうのは少ないみたいで(これは経営層じゃなくてむしろプログラマ側のコミュニケーションスキル問題の気がする)、とりあえず動いているように見えるものを作ることさえできれば、お金を握っているひとからお金を引き出すことは可能なんだな、ってことをそいつを見て理解した(またこいつが「コード読めないひと」をだますのがうまいんだ)。

で、ここで初めてタイトルにつながるんだけど、ようするにそれが「手に職」ってことなんだな、って思ったんだ。

詐欺ってのは言い過ぎにしても、「手に職」って言われる職業ってだいたい寡占なんだよね。たとえば資格がないとできない職業資格を持った人間の寡占状態にある。プログラムを書くのに資格必要ないけど、プログラムの読み書きは未だに特殊技能で(これは教育問題だと思う)、コードメンテナンス性の善し悪しを判断できるのもまたプログラマだけであるという意味でやっぱり寡占状態にある。

自分プログラマからこの寡占状態に恩恵にあずかっている側で、おかげで「ひとまず職にあぶれることはなさそうだな」っていう安心を得ることができているんだけど、この寡占状態って絶対不健全で、たとえば誰の目にも数字という形でわかりやすく現れてくる営業(一方から勝手見方で、営業の世界にもいろいろあるのかもしれない、イメージで語ってゴメン)だったら、「あい数字悪いな、切ろうぜ」ってなるレベル人間が「まあでも我々にはプログラマ世界はわからないからなぁ、彼は優秀っぽい雰囲気があるし」みたいな感じでお金をもらうことができるんだもん。

からやっぱり「手に職」って詐欺っぽい要素があると思う。だってそもそも「手に職があれば食うに困らない」って時点でおかしいじゃん。最低レベルの営業職と、最低レベル技術職、どっちも最低のはずなのに「俺は技術職で手に職があるから困らない」ってどう考えてもおかしくない?やっぱり詐欺だよこれって。

2014-07-17

関数型入門以前

これ読んでも関数型分からないけど、入り口の前あたりに立つために

関数型言語覚えたらなんの役に立つの

プログラマとしての引き出しが増える。

って書くと「そんなもんどんなプログラミングテクニックだって一緒だわ」って言われそうだけど、でもそうとしか言い様がない。

とりあえず、オブジェクト指向と同じで、プログラム構造化して、複数レイヤーに切り分けて部品化していくテクニックだとは言える。

ただオブジェクト指向とは大分切り口が違う。何ていうか、割と直交する切り口でプログラム構造を切り分けていく。

なので、関数型とオブジェクト指向と両方憶えるだけで、大分切り口の引き出しが増える。

オブジェクト指向関数型両方憶えると、プログラマとしての引き出し増やすのに効率が良い、って思えば良いかも。

具体的にどう切り分け方が違うの?

オブジェクト指向は、プログラムの各部品を「あれの中のこれの中のそれの中にあるあれ」みたいな感じで組み合わせる。

部品が更に細かい別の各部品で構成されていて、それぞれの部品が噛み合わさって、複雑な一つのプログラムを構成するような切り方。

関数型言語は、プログラム部品を「あれをした物にこれをした物にそれをした物にあれをする」みたいな感じで組み合わせる。

もっというとプログラム全体を簡単に記述するできるDSLがあって、そのDSLを簡単に実装するためのDSLがあって、DSLの入れ子構造で一番小さい部品シンプル関数、みたいな切り方。

どう使い分けたら良いの?

ケースバイケース。

ではあるんだけれど、シンプル部品を大量に組み合わせて構成するのがしっくりくるならオブジェクトで、部品数が少ないんだけど一個一個が複雑な動作する構成にしっくりくるのが関数型……かも?

関数型言語の紹介見てると、何かひたすらイミュータブルなデータを弄繰り回す説明ばっかり出てくるんだけど…

関数型言語たる条件として「関数が第一級オブジェクト」ってのがあるんだけど、関数が第一級オブジェクトだとイミュータブルなデータを素直に扱える。

で、イミュータブルなデータ構造使うと色々便利、ってことで実例として一番出てくるという。

何か型型言ってるんだけど、型くらいC言語にすらあるわ。メモリ領域の確保量を示すあれが何でそんなに重要なの?

関数型言語エポックメイキング的な言語が三つくらいあって、元祖Lispとその流れ汲んだMLMLの一種で関数型をある種の到達点に持っていったHaskellって感じ(独断偏見)。

で、このうちのMLって奴が、プログラミング言語に型システムがついてるんじゃなくて、型システムプログラミング言語がついてきた存在だったりする。

型で色々やるために生まれたわけで、まぁなんというかそもそも型と密接な関係にあって、Haskellもその流れを汲んでて、こいつが超有名になった、って感じ。

おかげさまで、型使って色々やったりする方法が日々考えられているわけです、静的型付関数型の世界では。

クロージャって、大まかな概念wikiとかで理解したけど、関数型でどう使われてるの?

関数型言語ではよく「関数関数を引き取って、合成した関数を返す関数」みたいなのが使われるんだけど、関数関数の合成って、それ合成された関数がもともと引数として与えられていた関数憶えてないと無理やん? 自分自身の構成部品憶えてられないわけだから

クロージャあると憶えててくれるわけですよ。

そんな感じで高階関数実用的なレベルで使うのには大体必須と言う。

モナドとやらは何に使うものなの? 何が便利なん?

関数型言語DSLを作りまくる言語みたいに書いたけど、モナドちょっと複雑なDSLを簡単に作らせてくれる仕組みだと思っとけば良い。

Haskell副作用が一切ない純粋関数型言語って言うけど、副作用なしでどうやって入出力してるの?

まず純粋定義だけど「全ての関数は同じ引数を与えられた際、必ず同じ値を返す」ってことで、これがいわゆる副作用がないって状態だ。

で、これって逆に言えば「プログラムである関数に対して、絶対に同じ引数を与えさえしなければ、その関数がどんな値を返したところで、事実上純粋だと言えてしまう」ってことでもある。

本末転倒感があるんだけど、HaskellではIOモナドという仕組みと特別main関数を使って「呼び出すたびに絶対に違う引数自動的関数に与えてくれる仕組み」を実現していて、こいつを使って入出力する。

うん……凄い本末転倒。ちなみにこの自動的に与えられる引数はRealWorldって名前がついていて、要は「刻一刻と変わり続け絶対に同じ状況にならない現実世界の状態を引数に取っちまっているようなもんだからしょうがないだろ?」的な感じ。

2011-09-23

「続 新しいプログラミングパラダイム」の目次


第1章 並行プログラミングGHC (上田和紀)
	1.1 はじめに
	1.2 ターゲットを明確にしよう
	1.3 はじめが大切
	1.4 GHCが与える並行計算の枠組み
		1.4.1 GHCにおける計算とは,外界との情報のやりとり(通信)である
		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 Temporal Prolog
	2.8 RACCO
	2.9 実現
	2.10 まとめと参考文献案内


第3章 レコードプログラミング (横田一正)
	3.1 はじめに
	3.2 レコードと述語の表現
	3.3 レコード構造とφ-項
		3.3.1 φ-項の定義
		3.3.2 型の半順序と束
		3.3.3 KBLLOGIN
	3.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 OBJ2
		4.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 プログラミングシステム FP
		5.2.1 オブジェクト
		5.2.2 基本関数
		5.2.3 プログラム構成子
		5.2.4 関数定義
		5.2.5 FPプログラミングスタイル
	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.5 FPプログラム翻訳
		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 カテゴリカル・コンビネータ理論CCL
	6.4 関数型プログラミングへの応用
		6.4.1 関数型プログラミング言語ML/O
		6.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.3 Knuth-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-Lisp
	9.4 リフレクティブタワー
	9.5 GHCにおけるリフレクション
		9.5.1 並列論理言語GHC
		9.5.2 GHC言語仕様
		9.5.3 GHCメタインタプリタ
		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章 マルセイユPrologProlog Ⅱ,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 マルセイユProlog
		3.3.1 Prolog記法
		3.3.2 Prolog計算規則
		3.3.3 Prologプログラムの例
		3.3.4 カットオペレータ
		3.3.5 DEC-10 Prologとの相違
	3.4 Prolog Ⅱ
		3.4.1 difオペレータ
		3.4.2 freeze
		3.4.3 ループ構造
		3.4.4 Prolog Ⅱのインプリメンテーション
	3.5 Prolog Ⅲ
		3.5.1 制約の枠組
		3.5.2 Prolog Ⅲのプログラム例
		3.5.3 束縛の領域と制約系
		3.5.4 Prolog Ⅲのインプリメンテーション
	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 Self
		5.3.5 動的束縛の意義
	5.4 対話性
		5.4.1 クラスの再定義
		5.4.2 表示機能の一体化
	5.5 オブジェクト指向の弱点
	5.6 まとめ


第6章 型推論ML (横田一正)
	6.1 はじめに
	6.2 LCFの超言語からMLへ
	6.3 プログラミング言語と型
	6.4 ML表現と型宣言
	6.5 ML型推論
	6.6 LCFへの応用
	6.7 まとめ


第7章 Miranda (加藤和彦)
	7.1 はじめに
	7.2 Miranda概観
		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 完備なTRS
		8.4.2 危険対
		8.4.3 危険対を用いたTRSの合流性判定
	8.5 Knuth-Bendixの完備化手続き
	8.6 KBの応用
		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 まとめ

2007-11-10

関数プログラミングにおけるFizzBuzz問題

いくつか考えてみた

(問1)高階関数再帰関数を必ず使って数値を要素とするリストの要素の総和を求める関数を書け。ただし高階関数を使うという要件と再帰関数を使うという要件は同じ関数で満たしてもよい。

(問2)二つの引数をとり二つのうち大きいほうを返す関数高階関数再帰関数をつかって数値のリストの最大値を求める関数を書け。ただし高階関数を使うという要件と再帰関数を使うという要件は同じ関数で満たしてもよい。

というのは簡単すぎるか?簡単すぎるなら

(問3)高階関数再帰関数を必ず使ってある数値に5を足し、10かけて2で割った数を求める関数を書け。ただし高階関数を使うという要件と再帰関数を使うという要件は同じ関数で満たしてもよい。

こっちの方がいいかな。でもトリッキーすぎる気もする。

一応問題を出したので、SchemePythonで自分で想定している答えを書いておいた。はてなではSchemeが人気のようなので、あまり知らなかったけど関数言語ではSchemeで書いておいた。Pythonで書くのはSchemeだけだとわかりにくいので、なにかスクリプト言語で書いておこうと思ったから。Rubyの方が人気なので、はじめはRubyで書こうと思ったけど挫折した。だれかRubyで書いてくれないかな・・・。コードオブジェクトってなによ。というか関数オブジェクトなのに引数にできないの?なんで?(以下疑問と愚痴の嵐なので略)Perlは古株が多くてユーザー数も多そうだけど、・・・その・・・無理です・・・。あの言語仕様はやる気がしない。ぶっちゃけ理解できない。Pythonを知らないひとは多そうだけど、知らなくてもSchemeよりは感じは掴めると思うのでPythonでも書いておくことにした。

Scheme

http://anond.hatelabo.jp/20071110215936

Python

http://anond.hatelabo.jp/20071110220132

これで大部分のひとがこの問題に興味をもたなくて解答するひとがいなくても、興味を持ったひとは安心だね!

追記:

問3で次のは無しとしておきたい。

Scheme

(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)

Python

def continuousApply(lst, obj):
    if lst:
        return continuousApply(lst[1:], lst[0](obj))
    else:
        return obj

def plus5(num):
    return num + 5

def times10(num):
    return num * 10

def divide2(num):
    return num / 2

def plus5_times10_divide2(num):
    return continuousApply([plus5, times10, divide2], 2)

plus5_times10_divide2(2)

Schemeによる解答

あくまで自分でこう答えるという話。

(問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なら上記の答えを応用して、似たような「手続き」を生み出す関数を作ることができる。

(define make-proceduce
    (lambda (fst . rest)
        (let ((lst (cons fst rest)))
            (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関数を一般的に作ることができ、型のメリットを享受しながらデメリットをなくすことができる。このように関数で手続きなんかを抽象化するときに型推論や多相型があると便利なのだ。

2007-11-09

Pythonではなぜ string.len() でなく len() なのか?

http://anond.hatelabo.jp/20071021143442

その理由は知らないが、なければ作ればいいじゃないか。

class MyString(str):
    def length(self):
        return len(self)

というクラスを作って

string = MyString("Hello world")
print string.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

sumUpThree関数テストすると

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))

Pythonラムダ式がだめだといわれているが、こんな風にかけたとして何がうれしいというのだ。

2007-09-01

9月になったし、もうそろそろ書いておくか

これから就職活動するバカはいないだろうけど、そういう人もいるだろうから少し書いておこう。

どちらかというと、アンチMS派なUnix技術者Windowsだけの世界で仕事をする辛さを。

Unix技術者は、業務実績にSolaris/AIX/Linuxって書いてあってもちゃんと質問しろ。Windows仕事は無いですよね?って。

僕が食べるために職を手にしているこのIT業界というのは、バッドノウハウMicroSoftExcelで出来ている。

その為、僕が手にしたUnixの知識は、特定の仕事以外でしか役に立たないし、使わない。

viだろうが、TeXだろうが、Xの知識よりも、MFCVBAのちょっとした知識のあるヤツが上にみられる。

ExcelWindowsの知識があればそれだけで仕事になるからだ。

いいか、viTeX、Xなんて捨てちまえ、Excelがあればそれでいいのだ。

Unix技術者でいうハッカーとはなんだろう。

MSでは、ActiveXを使ってCOMを操作し、クライアントレジストリを操作し、IE単体でできないことをやってしまうヤツがハッカーと思われている。

VBAマクロで作ったなんちゃってツールを3時間で作れるほうが、

perlruby/pythonで、より少ない時間で作ったツールよりも凄く思われてしまう。

そして、それができるヤツの方が、Unix技術者よりもよりハッカーであり、技術力があると思われている。

ブラウザを例にしたが、

javascriptでalert/confirmを出すよりも、vbscriptでMsgBoxの方が多くのことができるから、

javascriptNumberの計算よりも、vbscriptでDecimalを使った方が倍密度の計算ができるから、

vbscriptを駆使できるヤツは、凄く重宝される。

いいか、javascriptで汎用的に書くのなんてナンセンスだ。javascriptなんて捨てちまえ、覚えるのはJScript実装(WSH)だ。

この業界、何が不満になるかというと、

MSの、もっというとWindowsのことしか知らないヤツが多すぎるということ。

そういうヤツらは、Windowsだったらこんなこともできるのに、なぜUnix/Linuxだとこんなこともできないのか。と言う

そういうヤツらは、Windowsの未修正バグの合間を縫いながら中途半端な実装しかしない。

だって、中途半端(もしくは大雑把)な実装で動いているものの中で動くから。それ以上に実装しようとしてもできないのだ。

いいか、win32のメッセージングの仕組を覚えるんだ。無理矢理send_keyみたいなコードを書けるようにしろ。

コマンドを連結するよりも、結果に近いコードを書くんだ。線形になろうがヤツらは気にしないだろう。

ヤツらは、javapythonをバカにする。

何故か。

それは、.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というプラットフォームがあれば。



ああ、心が渇いていく。

 
ログイン ユーザー登録
ようこそ ゲスト さん