クロージャって何がいいの?at TECH
クロージャって何がいいの? - 暇つぶし2ch1:デフォルトの名無しさん
14/11/08 13:11:47.84 6V2MLUHb.net
関数型言語に必ずくっついてるこれ
いらんでしょ?匿名クラスで充分でしょ

2:デフォルトの名無しさん
14/11/08 13:17:58.06 rszc5DFq.net
マジレスすると、クロージャーよりも
関数内関数の方がいい。

クロージャーは変数スコープが不必要に広い。

多くの場合、クロージャーの外は見える必要がない。
逆に見えてしまうと不用意に変数を書き換えてしまう。

関数内関数がない言語が多いから
仕方なくクロージャーを使うしかないが、
Java8のラムダの方がまだ安全なコードを書くことが出来る。
(ラムダも外のスコープが参照できる場合があるので完璧ではない)

つまり俺がいいたいのは、クロージャーを使うと苦労するのジャー。

3:デフォルトの名無しさん
14/11/08 13:42:47.14 alIlcZLx.net
ディスクロージャ

4:デフォルトの名無しさん
14/11/08 14:33:50.79 Wb7Sa5AG.net
>>1
関数型言語の操作的意味論において、クロージャとは:
  「ラムダ式と局所環境とを組合せた概念」
を指す
このクロージャを具象構文で表したものが一般的な「ラムダ式」であり、
クロージャを識別子に束縛したものが一般的な「関数宣言」である

Standard ML という関数型言語だと、
たとえばラムダ式は fn x => x + 1 であり、関数宣言は val succ = fn x => x + 1 である
ここで、関数宣言には fun succ x = x + 1 と簡潔に書ける構文糖を用いるのが一般的
だから、あらゆる関数型言語ないし関数型プログラミングが可能なあらゆる言語であれば、
クロージャ(という概念)は必要不可欠に存在である、と言える

また Java の「匿名クラス」もクロージャ(という概念)を応用した具象構文の一種である
で、Java 8 で導入された「ラムダ式」もクロージャの具象構文だけど、
匿名クラスよりも簡潔に書ける利点があるから、多くのケースで広く利用されるようになるだろう
両者の間には、局所環境と組み合わせる対象が「匿名クラス」ではクラスという単位であるのに対して、
「ラムダ式」では式という(クラスよりも粒の小さな)単位であるという違いがある
目的に応じて適切に両者を使い分けることが望ましい

5:デフォルトの名無しさん
14/11/08 16:17:08.12 gNjtEENQ.net
  / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄\
∠                     ノ
 丶                      |
  ノ                        |
  |      / ̄ ̄ ̄ ̄\       |
  |     /            ヽ      |
  |     |             |     |
  |     |             |     |
  |     |             |     |
 /      |           |     /
 ヽ      \_/| |\_/    ヽヘ
  |         / \         /
   ̄ ̄ ̄ ̄ ̄ ̄     ̄ ̄ ̄ ̄ ̄ ̄
       パンとか止めるやつ

6:デフォルトの名無しさん
14/11/08 16:19:08.12 gwropNof.net
>>5
それ、パンとか止めるやつだろ!

7:デフォルトの名無しさん
14/11/08 16:28:06.78 Z0nNiFel.net
                / ̄ ̄\
               / _ノ  ヽ、_ \
             . | ( ●)(● ) |
         ,-,-,-,__ |  (__人__)  │rヽヽヽヽ__   「クイックロック バッグ クロージャー!!」
        r.l .' ' .'.r_l |   `⌒ ´   . | ´l   .|/
        .ヽ|   |   |           |  |   /_
      ._,,-ーヽ   /-‐ ヽ        /‐''",'  /.  `ヽ
     /   /`''‐-',.   ヽ      ./ rj,.-‐''´`l    ./
     \  |  二ヽ           ヽ三  |ー‐'´
       `''‐ヽ  ―`ヘ            j `―r'´
          `T ´   j.           ./   j
           ヽ   .ヽ、 ___  /   ,'
            |    ./(>)^ ヽ\   i
            |  ./  (_  (<) \ .i  
          / .! ./   /rェヾ__)⌒:::  ヾ.\
          /  ∧i.   `⌒´-'´  u;   ノ   ヽ
            |    .\ヽ 、  ,    /    |
         .ヽ    ',.  ー  一   ./     /
          ',   .',        ./   /
           .',   ',       /   /
           /ヽ、  \    /   /
           /  |   ヽ―‐/    ./ \
          ./   .l    丿  ゝ   (   ヽ
         /   /  /    \   ',    ',
         /   /-‐''´       `''‐|    ',
       ./   __|            . /     .',
       |    `ヽ、        ./ ̄     .|
       |      ヽ       /       /
       `"''-,,__ ,,,,丿       ゝ、__,,-''

8:デフォルトの名無しさん
14/11/08 18:29:54.75 +pW0VlFs.net
>>1
匿名クラスは嫌。

まぁ俺の用途では関数内関数で十分なことが多い。
なのでけっこう>>2には同意。

9:デフォルトの名無しさん
14/11/08 18:31:45.04 Z0nNiFel.net
>>8
最後の行に同意してくれてありがとう

10:デフォルトの名無しさん
14/11/08 21:41:30.87 1bx+kI6Q.net
おもてたんとちゃうこのスレ

11:デフォルトの名無しさん
14/11/08 22:16:16.20 BzSpEdoH.net
クロージャーってただのメソッド一つのクラスだろ

12:デフォルトの名無しさん
14/11/09 01:25:23.88 5LKfT6rZ.net
まじすか

13:デフォルトの名無しさん
14/11/09 02:04:06.76 8LiWtrih.net
という見方、扱い方もできるねって話だろ

14:デフォルトの名無しさん
14/11/09 03:36:21.74 Rov3GL+Ot
A{B{C}} というスコープがあるとき、一般的には、
C→Bのように、内から外はアクセスできるが、
A→Bのように、外から内はアクセスできない

ここで、Aからクロージャで、Bの内部関数Cを返すと、
Cは自分の外部環境Bを保持しており、
CからBをアクセスできるので、その結果、
AからBの環境にもアクセスできる

15:デフォルトの名無しさん
14/11/09 05:57:17.96 n2NDOrh4.net
ActionListenerなんて、実装当時にクロージャがあったら存在してたかどうか怪しいクラスだよね

16:デフォルトの名無しさん
14/11/09 07:54:16.27 6VpE/OBT.net
lispの方言かとおもった

17:デフォルトの名無しさん
14/11/09 09:19:55.73 nlmXbEn2.net
>>2
関数型言語では、基本的に変数を書き換えるのは例外的な操作だから
不用意に変数を書き換えることは殆ど無いし、
それなら環境が見えてる事のメリットの方が大きい

18:デフォルトの名無しさん
14/11/09 10:23:47.55 gYZvrVR/.net
>>11
複数にできるよ

19:デフォルトの名無しさん
14/11/09 16:16:30.86 K4BO8Ja1.net
関数内で関数が定義できる事とクロージャと何の関係があるんだ?
比較できるものじゃないでしょ

20:デフォルトの名無しさん
14/11/09 16:48:40.28 EbU/SVlS.net
まあ、クロージャは関数内関数の用途をも内包することは多いんじゃね?

21:デフォルトの名無しさん
14/11/09 17:24:14.45 xhtawW2X.net
>>17
それはあまり使われていない関数型言語限定の話ですね。

22:デフォルトの名無しさん
14/11/09 17:32:09.95 PiaxZAwM.net
>>1は関数型言語の話をしてるんじゃないのか。

> 関数型言語に必ずくっついてるこれ

23:デフォルトの名無しさん
14/11/09 17:38:41.70 50xVLBic.net
オレオレ言語仕様を考えてるんだけどさ今どの言語を見てもlambdaだらけじゃない
RAII出来る言語だとクロージャに環境掴まれるだけでリソースリークしそうなわけよ
ならイランでしょ?というわけでたてた

24:デフォルトの名無しさん
14/11/09 18:18:41.40 K4BO8Ja1.net
クロージャだからって外の環境全部掴む必要無いんじゃね
クロージャが使用してない変数については各スコープのタイミングで解放すれば十分じゃないの

25:デフォルトの名無しさん
14/11/09 18:20:47.86 xhtawW2X.net
evalが使える言語では、使用していないかどうか
実行するまでわからないのでそれは無理。

26:デフォルトの名無しさん
14/11/09 18:24:28.78 KOr7L+hP.net
>>21,21
関数型言語ではなく関数型プログラミングの話だと考えれば、
すでに多くの言語でクロージャという概念は幅広く普及していると言えるのではないかと
たとえば C#、Java8、C++11、JavaScript、Ruby 等々

もちろん Python のように、クロージャが存在しない手続き型言語も広く使われているけどね
また、C++ や Java でも古い規格だとクロージャは存在していなかった

27:デフォルトの名無しさん
14/11/09 18:40:07.36 lx9et4kr.net
Pythonの関数は外の環境掴んでるからクロージャ
嘘は良くない

28:デフォルトの名無しさん
14/11/09 18:40:57.06 nlmXbEn2.net
>>25
クロージャじゃなくてevalを禁止すれば良いんじゃね?

29:デフォルトの名無しさん
14/11/09 18:55:58.44 KOr7L+hP.net
>>27
>>26 で挙げたクロージャを備えた言語は、どれも外の環境を掴んで
ローカル変数に代入できる(=局所環境内の識別子に束縛できる)

それに対して,Python のラムダ式では外の環境を掴めないからクロージャではない
つまり Python は、クロージャを持たない手続き型言語

(ラムダ式ではなく)関数で外の環境を掴めるのは当たり前の話であり、嘘は良くない

30:デフォルトの名無しさん
14/11/09 18:59:22.34 KOr7L+hP.net
>>29 を訂正、ラムダ式(匿名関数)の話であるのを書き忘れていた

X:>26 で挙げたクロージャを備えた言語は、どれも外の環境を掴んで
O:>26 で挙げたクロージャを備えた言語は、どれもラムダ式の中で外の環境を掴んで

31:デフォルトの名無しさん
14/11/09 19:03:23.62 lx9et4kr.net
>>29
ラムダ式では代入は出来ないけど外の環境は掴んでるからクロージャ
嘘は良くない

32:デフォルトの名無しさん
14/11/09 19:08:15.30 nlmXbEn2.net
不毛だからケンカする前に用語を定義しろよ
オレオレ定義じゃないんだったら引用も必要

URLリンク(ja.wikipedia.org)

> クロージャ(クロージャー、英: closure)、関数閉包はプログラミング言語における関数オブジェクトの一種。
> いくつかの言語ではラムダ式や無名関数で実現している。引数以外の変数を実行時の環境ではなく、
> 自身が定義された環境(静的スコープ)において解決することを特徴とする。

33:デフォルトの名無しさん
14/11/09 19:13:25.68 nlmXbEn2.net
> (ラムダ式ではなく)関数で外の環境を掴めるのは当たり前の話であり、嘘は良くない

とりあえずelispにケンカ売ってるのだけは分かった

34:デフォルトの名無しさん
14/11/09 19:19:20.49 5LKfT6rZ.net
pythonのlambdaって外の環境見えないの?

35:デフォルトの名無しさん
14/11/09 19:22:02.17 lx9et4kr.net
見えるよ

36:デフォルトの名無しさん
14/11/09 19:25:16.21 5LKfT6rZ.net
そうだよね...

37:デフォルトの名無しさん
14/11/09 19:39:55.45 KOr7L+hP.net
>>31
C#、Java8、C++11、JavaScript、Ruby 等々の関数型プログラミングが可能な言語では、
どれも「ラムダ式の中であっても外の環境を参照し、それを局所環境に保存」できる

それに対して、Python だと「ラムダ式の中では外の環境を参照する」ことしかできない
つまり、手続き型言語の Python は関数型プログラミングには不向きである、と言える


>>32
>> 引数以外の変数を実行時の環境ではなく、
>> 自身が定義された環境(静的スコープ)において解決することを特徴とする。

クロージャを備えた言語ではクロージャ自身が局所環境を持つということだね(>>4 も参照)
だから、関数内でもラムダ式内であっても局所環境で変数を解決できる

それに対して(クロージャを備えず、代わりに)関数という実行環境しか持たない Python では、
関数内では変数を解決できてもラムダ式内で変数を解決できない
つまり、Python はクロージャを持たない手続き型言語

38:デフォルトの名無しさん
14/11/09 19:44:13.19 5LKfT6rZ.net
pythonのlambdaって単に単純な関数定義のシンタックスシュガーなんじゃないの?
lambdaなんて名前が付いてるからアレだけど。

39:デフォルトの名無しさん
14/11/09 19:44:17.88 KOr7L+hP.net
>>34
もちろん見えるよ

ただしクロージャが無いから、その(ラムダ式の中から)見えた値を局所環境に保存できない
関数の中ならば(関数が持つ)局所環境に保存できるんだけどね....

40:デフォルトの名無しさん
14/11/09 19:47:57.23 nlmXbEn2.net
>>37
・「変数を解決する」という用語が未定義
・「ラムダ式のみクロージャと認める」というのは>>32とは異なる定義だが、そのような定義をしている文献が引用されてない

やり直し

41:デフォルトの名無しさん
14/11/09 19:48:24.99 5LKfT6rZ.net
>>39
ラムダ式を評価した結果も関数定義を評価した結果も同じfunctionだよ。

42:デフォルトの名無しさん
14/11/09 20:00:59.51 lx9et4kr.net
>>41 たしかに

import inspect

def func(x):
return lambda n: x * n

func(5)(4) #=> 20 (Clojure)
inspect.isfunction(func) #=> True
inspect.isfunction(func(1)) #=> True

43:デフォルトの名無しさん
14/11/09 20:10:51.52 KOr7L+hP.net
>>40
>・「変数を解決する」という用語が未定義

失礼、言語処理系や言語意味論を知らない人には難しい表現だった

「変数を解決する」とは、変数に束縛された値を求めることを意味する
単純な実装では、変数と値の対(ペア)の集合である環境から、変数をキーに値を探索することで実現できる

>・「ラムダ式のみクロージャと認める」というのは>>32とは異なる定義だが、そのような定義をしている文献が引用されてない

「ラムダ式のみクロージャと認める」とは言っていないよ
C#、Java8、C++11、JavaScript、Ruby 等々の一般的な言語では関数でもラムダ式でも局所環境を持てる
これは「クロージャ自身が局所環境を持つ(>>4)」というクロージャ定義からすれば、自然な結果である
それに対して、ラムダ式では局所環境を持てない Python にはクロージャの概念が欠落しているんじゃないのか?
と指摘しているだけ

あるいは処理系への実装を失敗した?、あるいは言語設計上の欠陥を見落とした?という指摘と言い換えてもいい
Python の言語設計者達はクロージャの概念を知っているつもりだったのかもしれないけどね......

44:デフォルトの名無しさん
14/11/09 20:14:38.63 nlmXbEn2.net
>>43
お前こそ良く分かってなくて用語使ってるだろ
そういうのは変数の再束縛っていうんだよ
そんでお前は変数の再束縛と局所環境が持てない事を混同してる

45:デフォルトの名無しさん
14/11/09 20:19:48.73 5LKfT6rZ.net
pythonでは関数=クロージャなんじゃないの?
ラムダ式は関数定義の略記方だよ。

46:デフォルトの名無しさん
14/11/09 20:27:21.21 5LKfT6rZ.net
変数に束縛された値を求めることは評価するっていうんだと思う。
再束縛は別の値を束縛すること。

47:デフォルトの名無しさん
14/11/09 20:32:25.05 lx9et4kr.net
Lispっぽくクロージャ書けるよ

f = (lambda x:
(lambda y=2*x:
(lambda z=x*y:
(lambda w: w * (y + z))))()())
g = f(2)
g(3) #=> 36

48:デフォルトの名無しさん
14/11/09 20:34:00.52 KOr7L+hP.net
>>44
言葉を「変数の再束縛」へ言い換えただけでは、結論は同じだよ

C#、Java8、C++11、JavaScript、Ruby 等々の一般的な言語では関数やラムダ式はクロージャを元に
設計されているから、外の環境を参照した値を「局所変数に再束縛」できる
それが当たり前で、自然な関数型プログラミングができる

それに対して(クロージャを元にしていない)手続き型言語の Python では、
ラムダ式の中だと「局所変数に再束縛」できない
従って、手続き型言語の Python は関数型プログラミングには不向きである

49:デフォルトの名無しさん
14/11/09 20:34:54.87 nlmXbEn2.net
>>46
評価はPythonのラムダの中でも出来るよな?

50:デフォルトの名無しさん
14/11/09 20:37:14.94 nlmXbEn2.net
>>48
よし、あとはラムダの中で変数の再束縛ができないと
その言語にクロージャが無い事になるという文献を引っ張ってこい

51:デフォルトの名無しさん
14/11/09 20:40:33.21 lx9et4kr.net
>>48
Pythonのラムダ式では局所変数に再束縛できない、は間違い(>>47)
嘘は良くない

52:デフォルトの名無しさん
14/11/09 20:49:43.56 lx9et4kr.net
>>45
そうだよ

53:デフォルトの名無しさん
14/11/09 21:05:06.25 KOr7L+hP.net
>>48
クロージャを備えた言語であれば、ラムダ式を入れ子にした複雑なコードを書かなくても、
単純明瞭で可読性の高いコードが書ける

f = function(x) {
  y = 2 * x;
  z = x * y;

  return function(w) { return w * (y + z) }
}
g = f(2);
print(g(3));


これがクロージャを備えた C#、Java8、C++11、JavaScript、Ruby 等々の普通の言語と
関数型プログラミングに不向きな手続き型言語 Python との違い

54:デフォルトの名無しさん
14/11/09 21:08:04.55 lx9et4kr.net
ラムダ式の入れ子は分かりにくいから
関数型プログラミングに向いてない

関数型とは一体…

55:デフォルトの名無しさん
14/11/09 21:09:53.89 5LKfT6rZ.net
そもそも関数型プログラミングって堂々と代入してるようじゃダメなのでは

56:デフォルトの名無しさん
14/11/09 21:12:20.49 lx9et4kr.net
どれだけ間違いを指摘しても
Pythonにクロージャが無いって意見を上書きできない


これが参照透過性です

57:デフォルトの名無しさん
14/11/09 21:14:02.40 KOr7L+hP.net
>>53 の続き)
もちろん関数型言語であれば、>>53 の JavaScript より更に簡潔になるのは当たり前の話
以下は Standard ML

val f = fn x => let
    val y = 2 * x
    val z = x * y
  in
    fn w => w * (y + z)
  end
val g = f 2

g 3

58:デフォルトの名無しさん
14/11/09 21:18:46.76 KOr7L+hP.net
>>54
>ラムダ式の入れ子は分かりにくいから
>関数型プログラミングに向いてない

添削しよう:

 ラムダ式の入れ子は分かりにくいから、
 ラムダ式の入れ子や関数内関数を多用しなければならない手続き型言語の Python は
 関数型プログラミングに向いてない

それに対して、クロージャを備えた C#、Java8、C++11、JavaScript、Ruby 等々の普通の言語では、
クロージャ自身が持つ局所環境内の変数に代入(=束縛)できるから、
関数型プログラミングに向いている

59:デフォルトの名無しさん
14/11/09 21:25:01.25 KOr7L+hP.net
>>51
Python ができるのは、引数に再束縛することだけ
局所変数(>>53,56 の y と z)には代入できない

Python でも「ラムダ式では局所変数に再束縛できる」と主張したいのなら、
ラムダ式の入れ子や関数内関数を使わずに、可読性の悪い >>48 のコードを書き直しなさい
もし Python に真のクロージャが存在するのなら、簡単な仕事のはずだ

できるよね? できないのなら、嘘つきは君のほうだよ

60:デフォルトの名無しさん
14/11/09 21:31:21.14 lx9et4kr.net
変数に再束縛できないから、変数に代入できないに意見が変わったね
やっと>>31に追いついたね

61:デフォルトの名無しさん
14/11/09 21:36:16.07 lx9et4kr.net
>>47の変数は外から見えないという意味で
紛れもなく局所変数

62:デフォルトの名無しさん
14/11/09 21:41:46.54 LUEi6lWE.net
Java 8にクロージャなんかあったっけ?
ただのラムダだったような

63:デフォルトの名無しさん
14/11/09 21:44:14.34 KOr7L+hP.net
>>60,60
ぐだぐだ屁理屈を言うより、さっさと >>48 のコードを書き直した方がいいんじゃね?

それとも Python コミュニティでは >>48 みたいな
  ラムダ式を入れ子にしたカッコだらけ
のコードが可読性のある美しいコードなのかなあ
自分には、>>53,56 のほうが可読性の高いコードだと思うけどね

64:デフォルトの名無しさん
14/11/09 21:45:18.38 lx9et4kr.net
普通は関数定義するよ
当たり前じゃん

65:デフォルトの名無しさん
14/11/09 21:49:19.33 lx9et4kr.net
ところで関数はクロージャじゃないって
どこの文化なの?
聞いたことない

66:デフォルトの名無しさん
14/11/09 21:50:58.85 KOr7L+hP.net
>>62
>>4 で書いたように、クロージャは抽象的な概念だよ
言語の意味論を定義したり言語処理系を設計する時に用いられる抽象構文で現れる
この抽象構文上のクロージャは、具象構文では一般にラムダ式とか無名関数(匿名関数)と呼ばれる

たとえば Java 8 のラムダ式がそうだし、JavaScript の具象構文では function() { .... } と書き、
Standard ML では fn <id> => <expr> という具象構文で表現される

67:デフォルトの名無しさん
14/11/09 21:55:24.38 lx9et4kr.net
言語的にはJavaのラムダは
ただのメソッド一つのクラスだよ

68:デフォルトの名無しさん
14/11/09 21:58:19.30 KOr7L+hP.net
>>65
自分も聞いたことないね
そんなこと言ってるお馬鹿さんはいるのかな?

まあ正確に言うと、クロージャを識別子に束縛したものが関数だから、
束縛されていない無名関数(=ラムダ式)と区別することが必要な文脈もあるけどね(>>4)

69:デフォルトの名無しさん
14/11/09 22:04:34.10 lx9et4kr.net
>>68
じゃあPythonにクロージャはあるの?
Yes/Noで答えて

70:デフォルトの名無しさん
14/11/09 22:05:03.57 TZMLlS/6.net
Java 8のクロージャは「effectively finalに限りキャプチャ可能」
というなんちゃってな局所環境だけどな
effectively finalの導入でかろうじて使い物になるかも知れないレベル

71:デフォルトの名無しさん
14/11/09 22:10:31.90 KOr7L+hP.net
>>64
普通は局所変数に代入するだろ、>>53 みたいに
  y = 2 * x
  z = x * y

それとも、Python ではこんな単純な代入文も書かずに(書けずに?)、
わざわざ関数定義するのが当たり前なのかなあ?

72:デフォルトの名無しさん
14/11/09 22:13:13.99 n2NDOrh4.net
>>39
…Haskellにはクロージャが無いと?

73:デフォルトの名無しさん
14/11/09 22:21:17.10 KOr7L+hP.net
>>69
Yes/No であれば No だ

繰り返しになるけど、
真のクロージャを備えた C#、Java8、C++11、JavaScript、Ruby 等々におけるクロージャの定義と、
手続き型言語の Python におけるクロージャの定義は異なっている
Python では識別子に束縛したクロージャ、いわゆる関数しか存在できず、
局所環境を伴うラムダ式を表現できない

このため、>>48 のような
  ラムダ式が入れ子になったカッコだらけ
の汚いコードしか書けない
結果として、Python は関数型プログラミングには不向きである

74:デフォルトの名無しさん
14/11/09 22:21:52.15 lx9et4kr.net
>>71
だから普通はこう書くよ
あれ?一番簡潔になった?


def f(x):
y = 2 * x
z = x * y
return lambda w: w * (y + z)
g = f(2)
g(3)

75:デフォルトの名無しさん
14/11/09 22:25:17.72 lx9et4kr.net
>>68
そっちが言う馬鹿(>>73)がいたよ



まさかの同一ID⁉︎

76:デフォルトの名無しさん
14/11/09 22:28:55.78 GwhuA7Og.net
>クロージャを識別子に束縛したものが関数だから

C#やECMAScriptの匿名関数は関数ではないと。
珍妙な新説ですなふむふむ

77:デフォルトの名無しさん
14/11/09 22:31:31.78 KOr7L+hP.net
>>72
>>39における「値を局所環境に保存」とは、識別子と値の対(ペア)を局所環境に追加すること(>>43 も参照)

ここで、追加の時に既に同じ名前の識別子が存在していた場合、手続き型言語では値を破壊的に更新するけど、
関数型言語では新たに局所環境が生成される(=破壊的に更新しない)点が異なる
ただし、この追加時の振る舞いの差異は、クロージャが存在する/しないとは無関係、ごっちゃにするのは間違い

78:デフォルトの名無しさん
14/11/09 22:45:45.31 KOr7L+hP.net
>>74
たとえば JavaScript なら、ラムダ式だけ(>>53)と関数定義との併用、
それらのどちらでも簡潔なコードが書けるよ

function f(x) {
  y = 2 * x
  z = x * y
  return function(w) { return w * (y + z) }
}
g = f(2)
g(3)


結局、Python では「ラムダ式を放棄して」関数定義しなければ簡潔なコードを書けない、
ということが実証されてしまったようだね

つまり、真のクロージャを備えた C#、Java8、C++11、JavaScript、Ruby 等々のふつうの言語では、
ラムダ式だけでも関数定義との併用でも、ケースバイケースで選択して簡潔で可読性のあるコードを「書ける」けど、
手続き型言語の Python だとラムダ式だけでは「入れ子になったカッコだらけ」の汚いコード(>>48)しか書けないから、
常に関数定義で「書かなければならない」という違いがある

79:デフォルトの名無しさん
14/11/09 22:46:49.16 nlmXbEn2.net
>>77
お前のオレオレ定義なんて興味ねーんだよ
まずはその珍説が書いてある文献を引用しろ

80:デフォルトの名無しさん
14/11/09 22:49:23.73 5LKfT6rZ.net
>>78
>>45

81:デフォルトの名無しさん
14/11/09 22:51:44.34 lx9et4kr.net
>>78
関数定義で可読性も簡潔さも失わないから、関数で書ければ良いよ

で、なぜ関数定義でクロージャが作れる
Pythonにクロージャがない事になるの?
>>69にNoと答えて、>>65も否定したよね?

82:デフォルトの名無しさん
14/11/09 22:54:09.40 nlmXbEn2.net
>>80
そいつ、関数を定義する特定のシンタックスシュガーに制限があることと
その言語自体が持つ機能との区別が付かない馬鹿だから

83:デフォルトの名無しさん
14/11/09 22:56:01.93 5LKfT6rZ.net
でもまあ、pythonの文法が変態なのは間違いない。

84:デフォルトの名無しさん
14/11/09 22:56:21.23 KOr7L+hP.net
>>74
ナゼ Python では、以下のような簡潔なコードが構文エラーになるんだろうね?

f = lambda x:
  y = 2 * x
  z = x * y
  return lambda w: w * (y + z)
g = f(2)
g(3)

これじゃあ「Python は関数型プログラミングに向かない」と評価されてもしかたないよね
だって、真のクロージャを備えた C#、Java8、C++11、JavaScript、Ruby 等々のふつうの言語では、
>>53 みたいなラムダ式だけを使ったコードが何の苦もなく自然に書けるんだから

85:デフォルトの名無しさん
14/11/09 22:59:47.88 QKkGL4h0.net
83はキチガイなの?
>>74は明らかに実行時のy,zを取り込んだ関数オブジェクトを生成してるからクロージャだろ
defと書くかlambdaと書くか文法の些細な決まり事などどうでもいい

86:デフォルトの名無しさん
14/11/09 23:01:05.93 lx9et4kr.net
>>84
同程度に簡潔に書けるなら、書き方は一つの方が良い
というのがPythonの理想だから

87:デフォルトの名無しさん
14/11/09 23:08:28.24 KOr7L+hP.net
>>81
>で、なぜ関数定義でクロージャが作れる
>Pythonにクロージャがない事になるの?

>>73 で書いたように、真のクロージャを備えた C#、Java8、C++11、JavaScript、Ruby 等々の
ふつうの言語では(関数定義だけではなく)ラムダ式でもクロージャが作られるという違いがあるからだ
対して、Python のラムダ式ではクロージャが作られない(だから、局所変数へ値を代入できない)

もし「Pythonにクロージャがない」という主張が不適切であるのならば、
>>43 の最後で書いたように、
 「Python の言語設計者達は、処理系への実装を失敗した、あるいは言語設計上の欠陥を見落とした」
と言い換えてもいいよ

こんな使い物にならないラムダ式で満足しなければならないとは、最大の被害者は Python プログラマだよね
だって、他のふつうの言語であれば「ふつうに書ける」ことが、Python じゃ「書けない」のだから....(>>84)

88:デフォルトの名無しさん
14/11/09 23:13:26.40 5LKfT6rZ.net
ラムダ式の構文が残念だと言いたいなら、最初からそう言えばいいじゃん。

89:デフォルトの名無しさん
14/11/09 23:16:00.89 KOr7L+hP.net
>>85
ラムダ式が引数に値を束縛できるのは、関数型言語を知っていれば常識だよ
そんなことも知らないの?

で、引数以外の局所変数に値を束縛するには、純粋なラムダ式に加えてクロージャが必要になるって話だよ

90:デフォルトの名無しさん
14/11/09 23:18:21.66 G8K4RNhm.net
>ラムダ式が引数に値を束縛できるのは

それ束縛じゃねーだろ
キミはアホなのか?

91:デフォルトの名無しさん
14/11/09 23:18:59.88 nlmXbEn2.net
>>89
>>74のy, zのどこが引数なんだよ
既知外は黙ってろよ

92:デフォルトの名無しさん
14/11/09 23:23:03.86 lx9et4kr.net
>>47の話ならデフォルト引数で値を入れてるから
普通に関数適用で引数に値を入れてるのとは厳密には違うよ?
どうでも良いけどね

93:デフォルトの名無しさん
14/11/09 23:26:01.65 lx9et4kr.net
>>87
Pythonにクロージャが無いは嘘ってことね
嘘は良くない

94:デフォルトの名無しさん
14/11/09 23:27:54.79 KOr7L+hP.net
>>91
>>89で書いたのは >>42 のラムダ式だけで書かれた Python コードだ
失礼した

>>74 は関数定義でクロージャが作られているね
ただし、Python だけがラムダ式ではクロージャが作られず、
Python におけるクロージャの定義が他の「普通の言語」と異なっている事実に変わりはない

95:デフォルトの名無しさん
14/11/09 23:30:45.91 nlmXbEn2.net
>>94
お前は無名関数って何がいいの?スレを立てて、そこで思う存分Pythonのlambdaを罵倒するべき
クロージャ云々は言いたい事と噛み合ってない

96:デフォルトの名無しさん
14/11/09 23:33:02.09 KOr7L+hP.net
>>93
Python には真のクロージャが存在しない、という指摘は事実だよ(嘘ではない)

もし「Python にも真のクロージャが存在する」と主張したいのなら、
>>84 のコードが構文エラーとならないように添削しなさい
もし「Python にも真のクロージャが存在する」のなら、たやすい作業のはずだ
真のクロージャを備えた普通の言語では、何の苦も無く >>53 みたいなコードが書けるんだからね

君が嘘つきでなければ、書けるはず

97:デフォルトの名無しさん
14/11/09 23:33:22.37 5KptUVSU.net
使い勝手で一番使い物にならないのはJavaだろ?
void m() {
 int y = f();
 y = y + 1;
 new Thread(
  () -> {ここでyを使えないKUSO言語}
 );
}

98:デフォルトの名無しさん
14/11/09 23:33:25.09 5LKfT6rZ.net
ID:KOr7L+hP が言ってるのは、

関数の引数にもう少し複雑な処理をインラインで書きたいのに、
defは値返さねえし、lambdaは1行しか書けねえし、
まったく融通がきかねえな!

みたいな字面上の不満であって、関数型プログラミングだのクロージャだの全然関係ない。

99:デフォルトの名無しさん
14/11/09 23:36:58.94 lx9et4kr.net
>>96
関数は局所環境持ってても「真のクロージャ」じゃないってこと?
Yes/Noで答えて

100:デフォルトの名無しさん
14/11/09 23:39:26.26 nlmXbEn2.net
真のクロージャとかいうオレオレ用語
もちろん引用もなければ定義もない

101:デフォルトの名無しさん
14/11/09 23:40:53.08 KOr7L+hP.net
>>95
クロージャという概念を正しく理解していないと、
Python みたいなラムダ式に欠陥のある言語が設計されてしまうというお話だよ
言い換えると、クロージャという概念を用いると、
なぜ Python のラムダ式が欠陥品なのかを明解に説明できる

このクロージャの利点は、このスレの主旨からは逸脱していないと思うよ

102:デフォルトの名無しさん
14/11/09 23:42:02.22 nlmXbEn2.net
>>101
お前がこのスレで一番クロージャを理解してない件
構文の字面しか見てないし

103:デフォルトの名無しさん
14/11/09 23:57:43.62 KOr7L+hP.net
>>99
No だね

あえていえば「クロージャもどき」とか「なんちゃってクロージャ」だね
真のクロージャであれば無名関数でも間数定義でも作られ、
無名関数であってもクロージャを構成する局所環境を持つことができる
これが、 C#、Java8、C++11、JavaScript、Ruby 等々の
「ふつうの言語」における「ふつうのクロージャ」だ

おそらくクロージャを正しく理解していなかったんだろね、Python 言語設計者達は....

104:デフォルトの名無しさん
14/11/09 23:59:39.38 yjLcynWs.net
話をまとめよう

世間一般のクロージャの要件:
 局所環境を持つ(変数を束縛できる)
 関数をインラインで書ける

キチガイのクロージャの要件:
 クソージャの中にクソージャが書ける
 若しくは
 言語設計上の欠陥を見落としたことを認める(>>87の発言)
 のいずれか

105:デフォルトの名無しさん
14/11/10 00:08:24.74 LMH7nFF4.net
>>104
添削してあげよう


--
話をまとめよう

世間一般のクロージャの要件(C#、Java8、C++11、JavaScript、Ruby 等々):
 関数であっても無名関数であっても、局所環境を持つ(変数を束縛できる):>>53,56,77

Python に固有なクロージャの要件:
 関数だけが局所環境を持つ(変数を束縛できる):>>74
 無名関数では局所環境を持てない(変数を束縛できない):>>47,83

106:デフォルトの名無しさん
14/11/10 00:14:31.96 cCGgoLPL.net
まあここはscheme最強っていう事にしておきますか。

107:デフォルトの名無しさん
14/11/10 00:28:52.73 LMH7nFF4.net
>>102
> 構文の字面しか見てないし

だとすれば、Martin Fowler氏も「構文の字面しか見てない」ってもとになるんだろな

・Martin Fowler's Bliki in Japanese - クロージャ
 URLリンク(capsctrl.que.jp)

Lsip/Smalltalk/Ruby/JavaScript といったプログラミング言語では、
クロージャやブロックを多用したスタイルが好まれる
だから、Python みたいな無名関数で局所環境を持てない言語で同じようにクロージャを
多用するスタイルを試みると、「ラムダ式が入れ子でカッコだらけ(>>47)」な汚いコードや、
いちいち「関数定義しなければならない(>>74)」ケースと頻繁に出会うから、ストレスが溜まる
まあ「Python は手続き型言語」だから仕方ないんだよと自分に言い聞かせて我慢してるけど、
プログラミング言語を自由に選べるなら、真っ先に Python は除外するね、自分なら

もし、これが「構文の字面しか見てない」と思えるのなら、それはそれでもいいんじゃないのかもね.....

108:デフォルトの名無しさん
14/11/10 00:37:52.21 cCGgoLPL.net
Pythonはlambdaの不便さも含めて構文がアレなので大嫌いだけど、
ライブラリが色々そろってて便利だから結局よく使っているのであった。

109:デフォルトの名無しさん
14/11/10 00:42:53.31 zIX5GD/A.net
pythonのlambdaってmapやfilterを追加したときに申し訳程度に付けたって感じ

110:デフォルトの名無しさん
14/11/10 01:06:17.40 s5NqatD+P
だね。Python使いはlambdaが互換性のためだけに残ってる欠陥品って認識あるから
デモとかどうしても1行で書きたいときしか使わんけど、
シンタックスシュガーの実体がlambdaな方面からするとそんな事情しらんしキモいかもね。
defで名前付きで書くのがふつうだし機能上困ってない。

111:デフォルトの名無しさん
14/11/10 02:52:22.03 qQmxJFhq.net
>>107
その文章を書いた人の考えと、君の解釈には随分とズレがあるようだ

112:デフォルトの名無しさん
14/11/10 06:04:53.17 i3Y7RgoA.net
馬鹿には無理

113:デフォルトの名無しさん
14/11/10 07:14:42.95 0mRy26rG.net
Pythonの不自由さ(関数型のクロージャに近いの)はGuidoの方針じゃないの?
嫌なら、おとなしくジェネレータ使えばいいじゃん。

114:デフォルトの名無しさん
14/11/10 08:48:39.72 PWSP4TjP.net
クロージャは何がいいんだよ!
URLリンク(i.imgur.com)

115:デフォルトの名無しさん
14/11/10 09:04:03.39 HTkQymog.net
引数に別名付けたくなる程に中身が長いなら
関数にも名前付けろってのがGuidoの方針なんだろ
文法的に拡張可能なのに、あえてリジェクトしてるくらいだし
URLリンク(www.artima.com)

116:デフォルトの名無しさん
14/11/10 10:20:30.55 CeTPRNSr.net
>>107
Martin Fowlerは字面だけを見てないから、ちゃんとPythonにもクロージャがあると思ってるよ

お前が張ったリンク先の「他の言語」を見てみろ

117:1
14/11/10 11:39:28.98 rdbd3Lyi.net
何がクロージャかよりどこが好きかでクロージャを語れよ!!(ドンッ

118:デフォルトの名無しさん
14/11/10 20:33:09.35 AR7BQCkT.net
クロージャとメソッドで f[x] と f(x) を使い分けなきゃダメなRubyが
一番ウンコだと思う

119:デフォルトの名無しさん
14/11/10 20:39:42.07 5eyjbk6/.net
>>118
それはクロージャとメソッドではなく、Procとメソッドだと思う
Rubyのクロージャはブロックのほうの機能と考えたほうが良いんじゃないかな

120:デフォルトの名無しさん
14/11/10 21:34:09.37 Xzn5T3EF.net
>>117

俺の財宝か?欲しけりゃくれてやる。
探せ!この世の全てをそこに置いてきた。

121:デフォルトの名無しさん
14/11/10 22:47:25.14 oQ75X8QG.net
文系出身プログラマ「クロージャ?なにそれ?服入れるとこ??」
ってやつに対してドヤ顔ができる

122:デフォルトの名無しさん
14/11/11 06:32:45.68 G8l0apNf.net
クロー系の最強魔法です 消費MP60

123:118
14/11/11 21:00:28.44 UknPa1bY.net
レスお願いします

124:デフォルトの名無しさん
14/11/11 22:06:02.40 3gT2I0NB.net
若い時に買ってでもすることは?

苦労じゃ!くろうじゃ!クロージャ!

125:デフォルトの名無しさん
14/11/12 01:25:01.41 G1/eYMX4.net
クロージャの良さを、クロージャを使うことで劇的に
簡潔になる例を使って説明してください

126:デフォルトの名無しさん
14/11/12 07:27:28.43 ptlTHlgg.net
コールバック関数を別途書かなくて良くなります。
もしコールバック関数の為だけにインスタンス変数を定義していたなら、
それも必要が無くなります。

消費MP 5

127:デフォルトの名無しさん
14/11/12 08:10:30.04 G1/eYMX4.net
コールバック関数地獄のJSのコードは
可読性が悪い上に簡潔でも無いので、失格です

128:デフォルトの名無しさん
14/11/12 08:13:15.39 /hly7+iy.net
オールバックって額からハゲるだろ?

129:デフォルトの名無しさん
14/11/12 08:27:11.27 cKuXIrT/.net
>>127
そんなあなたにClojureScript。
core.asyncのチャネルでスッキリしますよ(Go由来のようだけど)

130:デフォルトの名無しさん
14/11/12 20:27:05.24 3VJGATlA.net
>>129
コールバック自体がダメなんだよ。
例えば、addEventLisnerの引数にコールバックを指定する。
これだけでも可読性悪いだろ。

131:デフォルトの名無しさん
14/11/12 20:37:53.49 L8labB6g.net
見慣れてるかどうかだと思うけどな

132:デフォルトの名無しさん
14/11/12 20:38:24.71 5GyhUZuz.net
>>130
代案も出さずに批判だけするなら、幼稚園児にだってできるよ

133:デフォルトの名無しさん
14/11/12 20:52:00.80 UPi6O5bX.net
リスナーI/Fをインプリメントしたオブジェクト渡せばいいのでは

134:デフォルトの名無しさん
14/11/12 21:14:25.68 ptlTHlgg.net
それではそのオブジェクトを定義しなくてはならなくなります。
クロージャはそのようなデリゲートオブジェクトやコールバックパターンからの解放なのです。

消費MP 12

135:デフォルトの名無しさん
14/11/12 21:16:45.87 eep146vT.net
JavaScript(だけに限らないが)
クロージャーが見難いんじゃなくて
非同期の入れ子が見にくいんだろ。
で、それを解決するライブラリが存在する。

結局のところ、そのライブラリ
Promiseとかを使えば解決する問題。

136:デフォルトの名無しさん
14/11/12 21:23:36.45 G1/eYMX4.net
結局のところ、コールバックはクロージャのメリットじゃないんですね?
もっと良い方法があるのですから

137:デフォルトの名無しさん
14/11/12 21:36:55.56 ptlTHlgg.net
いや、クロージャ使ってそのスコープで解決しちゃえばコールバック関数要らないって話なんだが。

138:デフォルトの名無しさん
14/11/12 21:59:20.14 G1/eYMX4.net
Haskellのdo記法みたいなのがあれば
クロージャをチェインしていっても読み難くならないという話ですか?

139:デフォルトの名無しさん
14/11/12 22:58:17.02 L8labB6g.net
小規模なコールバックだったらインラインで書いた方が見通しが良いだろうし、
複雑なのだったら分けて書いた方が理解しやすいだろうし、
あれが最強他はゴミとか言ってるのが一番ダメなんじゃね?

140:デフォルトの名無しさん
14/11/15 12:17:49.98 uUcubJGq.net
結局クロージャの利点てコールバックが楽にかけるってだけ?
ならクロージャや匿名オブジェクトじゃなくて匿名メソッドが書ければ充分だな

141:デフォルトの名無しさん
14/11/15 12:25:31.04 u4ZMuG60.net
楽に書けるって事じゃなくて、そのスコープで完結できるって事じゃね?

142:デフォルトの名無しさん
14/11/15 12:56:58.32 XlhMXrhL.net
とりあえずコードで語れば?
大規模開発でメリットが出てくるとかの話じゃないんだし

143:デフォルトの名無しさん
14/11/15 14:40:16.71 EFct/v5k.net
見た目的にも変数の値の可視性的にもそこのスコープってとこが楽だよね

144:デフォルトの名無しさん
14/11/15 14:43:26.00 XlhMXrhL.net
つまりインラインでクラス定義できるのでも良いわけだよね

145:デフォルトの名無しさん
14/11/15 15:14:55.72 EFct/v5k.net
>>144
本来そうだけど 、
シンタックスはインラインだけど実際はただの内部クラスで、
生成時の環境を一切利用できない言語もあるから何とも言えない。

クロージャの代わりにクラスを用いると何となくそういう実装になる。
ローカル環境の代わりにインスタンス変数を用いる方向にいくから。


FILE *fp = fopen(..);
doHoge( ^(const char*msg){ fputs(msg,fp); });
fclose(fp);

みたいに簡便にクロージャ生成時の外部の変数(の値のコピー)を
保持し使用できるクロージャとは方向性が違う。

ローカルメソッドに至っては環境が一昨渡せない
シングルスレッド前提ならグローバル変数を使えばいいわけだけど

146:デフォルトの名無しさん
14/11/15 15:54:48.49 uUcubJGq.net
(擬似言語)
fw = new FileWriter();
doHoge( fw.witer );
fw.close();
こんなのをワンラインで書ければ満足なんだろ?匿名メソッドで十分じゃない

147:デフォルトの名無しさん
14/11/15 15:58:46.71 EFct/v5k.net
>>146
じゃ匿名メソッドで書いてごらんよ

148:デフォルトの名無しさん
14/11/15 23:46:47.75 JsFAZjCZ.net
with (fw, new FileWriter()) {
doHoge(fw.witer);
}
こうやって書けるほうがいい

149:デフォルトの名無しさん
14/11/16 10:37:06.14 ZMiOBdAw.net
じゃあこれは?

FILE *fp = fopen(..);
doHoge( ^(const char*msg){ fprintf(fp, "Hoge: %s\n", msg); });
fclose(fp);

150:デフォルトの名無しさん
14/11/16 11:54:54.13 fx2XWh+X.net
>>148
もはや匿名メソッドすら要らない派が出てくるしww

151:デフォルトの名無しさん
14/11/18 16:33:41.48 cuxiU0eb.net
Java8すら使わせてもらえない人が必死なスレにしか見えなくなってきた

152:デフォルトの名無しさん
14/11/19 22:27:12.37 eeZRz+g3.net
>>146,147
それだと doHoge の実行中に例外が発生するとファイルがクローズされない

たとえばクロージャを多用する Ruby のような言語だと、以下のように書く
 File.open(..) do |file|
   doHoge do
     file.puts(msg)
   end
 end
Ruby ではクロージャをブロックと呼ぶけど、ブロック実行中に例外が発生しても
ファイルは確実にクローズされるし、ユーザ定義メソッドでも同様な振る舞いを実装できる


>>148
それに対して、クロージャを持たない手続き型言語の Pascal や Python といった言語では、
同じ事をするのに(>>148 のような) with 構文を使わなければ書けない
クロージャは一級市民だから引数で渡したり呼び出すことができるという自由があるけど、
with 構文はあくまで文(statement)だからクロージャと比較すれば表現力は制限される
いわばクロージャという概念を持たない言語の代用品が with 構文である

なおJavaScript はクロージャと with 構文のどちらも持っているけど、
書籍 "JavaScript: Good Parts" だとクロージャは Good Parts に
with 構文は Bad Parts に分類されている

153:デフォルトの名無しさん
14/11/19 23:00:05.80 074lLX1H.net
クロージャばりばり使うlisp方言でもwith構文は使うよ

154:デフォルトの名無しさん
14/11/19 23:12:18.42 3WdraWBV.net
クロージャとクリーンアップ処理とは別の話じゃないの?

155:デフォルトの名無しさん
14/11/19 23:33:41.68 PA9iCB5s.net
Pythonが憎すぎて既知外になった人の相手をしちゃいけません

156:デフォルトの名無しさん
14/11/19 23:39:01.13 QzanlTyB.net
>>152
> なおJavaScript はクロージャと with 構文のどちらも持っているけど、
> 書籍 "JavaScript: Good Parts" だとクロージャは Good Parts に
> with 構文は Bad Parts に分類されている

お前バカじゃね? 大馬鹿じゃね?

ここで言ってるwithは例外が起きた時にリソースを解放する機能を持ったもの。
JavaScriptのwithはそんな機能は持っておらず、

obj.foo() を
with(obj) {
  foo()
}
と書けるようにするためでしかなく、それによる問題(詳しくは調べて)があるから
Bad Partsになってるだけ。
PascalやPythonのwithがBad Partsになってるわけじゃない

お前、ほんと、馬鹿だよね?

157:デフォルトの名無しさん
14/11/19 23:57:41.67 eeZRz+g3.net
クロージャと with 構文のどちらも持っている言語であれば、
ケースバイケースで可読性や好みで使い分ければいいのではないかと

問題はクロージャを持たない、あるいは
「世間一般のクロージャの要件(>>105)」を満たせない言語では、
with 構文という(クロージャと比べて)不自由な代用品を使わざるをえない
という話

158:デフォルトの名無しさん
14/11/20 00:02:30.91 fhZ8V3Hu.net
>>152>>157
下の(a)と(b)が等価であるようなJSのwith構文と
リソース解放のwith構文の区別もつかないような馬鹿が
何書いても説得力無いよ


// (a)
with (obj) {
    a = b;
}

// (b)
if (obj.a === undefined) {
    a = obj.b === undefined ? b : obj.b;
} else {
    obj.a = obj.b === undefined ? b : obj.b;
}


withって字面だけ見て同じだと思っちゃったの?
そんなだから構文の字面しか見てない馬鹿って言われちゃうんだよ

159:デフォルトの名無しさん
14/11/20 00:19:03.39 wJ3BgpRF.net
>>156
>ここで言ってるwithは例外が起きた時にリソースを解放する機能を持ったもの。

わざわざ with という構文を追加して言語の意味論を複雑にしなくても、
もし汎用的な概念であるクロージャがあれば、同じ事を実現できるってことだよ

もし Python にもクロージャがあるなら、他の言語達と同様に
with 構文を使わなくてもリソースの自動解放を簡潔に表現できるハズだけど、
手続き型言語の Python では無理だろうね

それとも、書けるかな?

160:デフォルトの名無しさん
14/11/20 00:20:15.54 7GcQ+ika.net
pythonでも引数にクロージャ受け取ってwithの中でそれを実行する関数つくれば、rubyのそれと等価じゃね?
pythonはlambdaが制限きついから複雑な処理はインラインには書けないけど。

161:デフォルトの名無しさん
14/11/20 00:29:37.23 wJ3BgpRF.net
>>160
>それを実行する関数つくれば、

もし Python が「世間一般のクロージャの要件(>>105)」を満たしていれば、
「関数をつくらなくても」クロージャだけで簡潔に書けるはず
つまり「関数をつくらなければ書けない」ということは、
Python が「世間一般のクロージャの要件」を満たしていないことを認めたってこと

162:デフォルトの名無しさん
14/11/20 00:36:40.77 ri7Qzvfi.net
「世間一般のクロージャの要件」が
全然世間一般の定義じゃない件

163:デフォルトの名無しさん
14/11/20 00:37:00.07 7GcQ+ika.net
>>161
def make_f(x):
 def f(y):
  return x * y
 return f

例えばこんなのがあったとして、このmake_f()が返すものは何?

164:デフォルトの名無しさん
14/11/20 00:42:39.12 wJ3BgpRF.net
>>163
「クロージャみたいなモノ」もしくは「クロージャもどき」

def make_f(x):
 return lambda(y): x * y

が返すのも同じ

165:デフォルトの名無しさん
14/11/20 00:44:55.24 7GcQ+ika.net
>>164
「クロージャみたいなモノ」もしくは「クロージャもどき」と、クロージャの違いは何?

166:デフォルトの名無しさん
14/11/20 00:45:40.70 ri7Qzvfi.net
>>164
>>32の定義だと完璧にクロージャの条件を満たしてるけど?

君はどこのローカルルールの話をしてるの?

167:デフォルトの名無しさん
14/11/20 00:47:27.27 wJ3BgpRF.net
>>165
>>105

168:デフォルトの名無しさん
14/11/20 00:52:13.60 7GcQ+ika.net
>>167
>世間一般のクロージャの要件(C#、Java8、C++11、JavaScript、Ruby 等々):
>  関数であっても無名関数であっても、局所環境を持つ(変数を束縛できる):>>53,56,77

>>163のmake_f()が返すものは局所環境をもってるし名前も付いてないよ。

169:デフォルトの名無しさん
14/11/20 00:58:03.79 wJ3BgpRF.net
>>166
いや、Python は関数を定義しなければ局所環境が作られないんだから、
>>32 の要件は満たしていないだろ
>>32 には「ラムダ式や無名関数で実現している」と書かれているんだけど、
日本語が不自由なんですか?

実際、もしも >>32 の定義を満たしているなら、
>>47 のゴチャゴチャしたコードは
(>>74 のようにわざわざ関数を定義しなくても)
>>84 のように「ラムダ式や無名関数で実現している」
簡潔なコードに書き直せるはずだ

さて、論よりコード、>>166 は書き直せるかな?

170:デフォルトの名無しさん
14/11/20 01:00:19.64 fhZ8V3Hu.net
今の議論と全然関係ないんだけど、久しぶりにTIOBEを見たら
ちょっと前までPerl, Python, Ruby, PHPで順位を争ってたのに
いつの間にかRubyだけ人気無くなっててワロタw

URLリンク(www.tiobe.com)


だからRuby信者発狂しちゃったの?


1 C
2 Java
3 Objective-C
4 C++
5 C#
6 PHP
7 Python
8 JavaScript
9 Perl
10 Visual Basic .NET
11 Visual Basic
12 R
13 Transact-SQL
14 Ruby
15 Delphi/Object Pascal
16 F#
17 PL/SQL
18 Swift
19 Pascal
20 Dart

171:デフォルトの名無しさん
14/11/20 01:03:38.95 ri7Qzvfi.net
>>169
>>32には「いくつかの言語では」と前置きされてるじゃん
つまりラムダ式や無名関数は必要条件ではない

そっちこそ日本語が不自由すぎるのでは?

172:デフォルトの名無しさん
14/11/20 01:04:53.19 wJ3BgpRF.net
>>168
それは def f(x): で関数を定義しているから、当たり前の話

「世間一般のクロージャ」であれば、わざわざ関数を定義しなくても
ラムダ式や無名関数と呼ばれる構文でクロージャを作れるんだよ
>>32 をよく読み直そうね

173:デフォルトの名無しさん
14/11/20 01:06:05.89 7GcQ+ika.net
>>172
じゃあさ、これが返すものは何?
(define (make_f x)
 (define (f y)
  (* x y))
  f)

174:デフォルトの名無しさん
14/11/20 01:07:50.18 fhZ8V3Hu.net
>>172
> >>32 をよく読み直そうね

お前が100回読み直した方が良いぜw

175:デフォルトの名無しさん
14/11/20 01:10:58.55 wJ3BgpRF.net
>>171
>>32 にある「いくつかの言語では」という前置きは、
後から出てくる Smalltalk や Ruby のブロック構文を指すと
考えるのが自然じゃないかな?

さすがに Wikipedia のページ著者が
「ラムダ式や無名関数」と「関数定義」との違いも
分からないほどのお馬鹿さんだとは思えないしね

176:デフォルトの名無しさん
14/11/20 01:11:10.32 7GcQ+ika.net
>>173
ごめん。それで (make_f 10) とか実行した時に返ってくるもの、の間違い。

177:デフォルトの名無しさん
14/11/20 01:15:12.19 wJ3BgpRF.net
>>173
クロージャだね

(define (make_f x)
 (lambda (x) (* x y))
)

が返すのもクロージャだね

178:デフォルトの名無しさん
14/11/20 01:18:52.68 7GcQ+ika.net
>>177
>>163のpythonのコードと完全に同じなんだけどw

179:デフォルトの名無しさん
14/11/20 01:18:56.43 fhZ8V3Hu.net
>>175
> さすがに Wikipedia のページ著者が

Wikipediaの編集者を持ち上げるのは良いけど、
お前の主張とは違う事が書いてあるぜ
読めるか?Pythonって書いてある

> クロージャを持つ言語に、C# 3.0、C++11、ECMAScript(JavaScriptを含む)、Groovy、Java 8(予定)、
> Perl、Python、Ruby、PHP(5.3以降)、Lua、Squirrelなどがある。

180:デフォルトの名無しさん
14/11/20 01:28:21.39 wJ3BgpRF.net
>>179
Wikipedia の記事が常に 100% 正しいと思っているのかな?

記事の冒頭にある >>32 のクロージャという用語の定義とは
矛盾していると思うけどね
(自分のクロージャという用語の定義は >>4 で書いた)

もし矛盾していないと反論したいのなら、論よりコードだ
>>47 のゴチャゴチャしたコードは
(>>74 のようにわざわざ関数を定義しなくても)
>>84 のようにラムダ式や無名関数だけで書き直せるはず

さて、>>179 は書き直せるかな?

181:デフォルトの名無しさん
14/11/20 01:32:42.88 fhZ8V3Hu.net
>>180
>>171が正解と考えれば全く矛盾してないので、お前が間違ってるんだよ

182:デフォルトの名無しさん
14/11/20 09:44:37.50 BfhGUngW.net
with構文はスコープから抜ける時にclose的な関数を必ず呼び出してくれる保証があるけど、
Rubyのブロックにはそんな保証は無い
だからRubyではウッカリcloseを忘れても分かりにくい
そういうのは良くない

183:デフォルトの名無しさん
14/11/20 11:08:08.37 nwROesTX.net
>>180
> Wikipedia の記事が常に 100% 正しいと思っているのかな?

思ってないけど、あんたが言っていることよりかは
正しいと思うね。

だって、あんたの言うことのほうが正しいなら
wikipediaを修正すればいいわけだから。

184:デフォルトの名無しさん
14/11/20 12:57:07.44 5gFBGGbj.net
なんだ、この偏執狂たちの罵り合いはw

そんなことより、問題。
若い内に買ってでもしろ、と言われるものはなぁんだ?

185:デフォルトの名無しさん
14/11/20 15:15:51.24 W3M4RtQD.net
ああ、let-inが無いからpythonのはクロージャじゃないって主張か。
斜め上だな。

186:デフォルトの名無しさん
14/11/20 16:40:50.21 2szoNUEC.net
環境と変数を手軽に包めるのは有難いけどなあ
XMLベースのジョブ管理言語とか
ちょっとしたVM作るときに
継続の表現にクロージャなしだとだるいよ
さらに無名クラスも無い言語だと
本物のVM作らなきゃいけなくなる

187:デフォルトの名無しさん
14/11/20 20:12:20.93 IqIimPum.net
URLリンク(developer.mozilla.org)

188:デフォルトの名無しさん
14/11/21 13:07:27.23 obtZMam2.net
>>184
セックス…かな
年とると立たなくなるから

189:デフォルトの名無しさん
14/11/21 13:13:28.47 zygDXSz1.net
>>188
ご愁傷さまです。

190:デフォルトの名無しさん
14/11/29 13:01:53.24 OX49RFg5.net
>>190


191:デフォルトの名無しさん
14/12/10 19:56:15.27 veDvxwge.net
Swift スレでクロージャの話題で荒れそうだったので、こちらへ移動しとく
 スレリンク(tech板:153番)

--
Swift や Ruby を含む多くの言語では常識であるけど Python では異なるものとして、
関数型言語に由来した(無名関数やラムダ式とも呼ばれる)クロージャがある
たとえば "The Swift Programming Language" の "Closure" の章にある map メソッドを使った
サンプルコードは、Ruby でも同じスタイルの良く似たコードで書き直せる:
 URLリンク(ideone.com)
これは Ruby だけでなく、JavaScript でも同じ
Swift や Ruby と比べて構文が簡潔な JavaScript ではいくらか冗長にはなるけれど、
何の苦もなく Swift と同じスタイルで書き直せる:
 URLリンク(ideone.com)

同様に、「あるテーブルから特定の行だけを抽出し、加工して、集計する処理」は、
Swift だと table.filter { .... }.map { .... }.reduce { .... } とメソッドを連結(チェイン)させた式で書ける
これは Ruby なら table.select { .... }.map { .... }.inject { .... } と書き直せる
ここで、クロージャ内の ..... の部分には、上記のサンプルのように「任意の文(statements)が書ける」

もしかすると、いやこんなの高階関数のプログラミングを知っている人なら当たり前だろ、と感じるかもしれない
ところが Python だけはクロージャの本体に(任意の文ではなく)「式(expression)しか書けない」:
 URLリンク(ideone.com)  # --> Syntax Error になってしまう
だから、他の言語のクロージャに相当するコードを(名前のある)関数としてわざわざ宣言しなければならない:
 URLリンク(ideone.com)

結果として、Python は手続き型プログラミングであれば簡潔で可読性に優れたコードが書けるスクリプト言語だけれど、
関数型プログラミングには適さず、こうした関数型プログラミングは推奨されていないらしい(これを "酸っぱい葡萄" と言ふ)
 スレリンク(tech板:70-71番)

これが Swift や Ruby 等と比較すると、関数型プログラミングで Python が劣る典型的な一例になる

192:デフォルトの名無しさん
14/12/10 20:24:01.24 Q728OFWk.net
と言うかどう見てもこないだまでこのスレに居た俺俺定義の人ですな

193:デフォルトの名無しさん
14/12/10 20:43:29.64 Q728OFWk.net
よく見たら、そのスレで誘導かけてるの、話振ったお前本人じゃねーかw
俺俺定義が認められなかったから逃げて来たのか?

194:デフォルトの名無しさん
14/12/10 21:30:40.85 AwBDqpLr.net
クロージャの定義は>>4って書かれてたがStandard MLにラムダ式はない
けど当然SMLにはクロージャがあるわけで
ソースはThe Definition of Standard ML, revised edition

195:デフォルトの名無しさん
14/12/10 21:46:37.74 ZY5znPCs.net
関数型プログラミングってどういうのを指して言ってるんだろ

196:デフォルトの名無しさん
14/12/10 21:50:32.14 gkNqf6iG.net
>>191のサンプルが手続き型全開の書き方で笑った


>>195
関数(に名前付けたくない)型プログラミング

197:デフォルトの名無しさん
14/12/11 21:30:20.83 GpAyUabF.net
>>193
Swift スレの質問「Python が Swift や Ruby より劣ってるのは何か」に答えただけ
で、具体的に反論できないから罵倒を始めて Swift スレが荒れそうだったから、
こちらへ移動してきた


>>194
>>4 の定義において、局所環境やラムダ式は(クロージャという概念の構成要素であるけど)、
一般の言語だと直接的に対応する具象構文として存在していない(自分は知らない)
その書籍は読んでいないけど、おそらく Standard ML では "fn" <match> という具象構文を
「関数(function)」または「関数式(function expression)」と呼んでいると思う
>>4 だと、その具象構文 "fn" <match> はクロージャに対応する

またクロージャ(日本語では「閉包」)という用語は馴染みづらいので、
クロージャの具象構文を指して(便宜的に)無名関数/匿名関数/ラムダ関数/ラムダ式/関数式 ...etc と
別名で呼ばれることがある:
・Standard ML では、単純に「関数」や「関数式」と呼ぶ
・JavaScript では、"ECMAScript Specification" では(SML と同様に)「FunctionExpression」と呼ばれ、
 サイ本では「関数リテラル」と呼ばれている
  ・13 関数定義 (Function Definition) -- Under Translation of ECMA-262 3rd Edition
    URLリンク(www2u.biglobe.ne.jp)
・Python では、その言語リファレンスで「ラムダ式」と呼ばれている:
  ・6. 式 (expression) ― Python 3.4.2 ドキュメント
   URLリンク(docs.python.jp)

198:デフォルトの名無しさん
14/12/11 21:48:16.84 AENhOzwc.net
>>197
肝心のクロージャの定義の引用はまだですか?
俺俺定義はお腹いっぱいなんですよ

199:デフォルトの名無しさん
14/12/11 22:44:15.05 GpAyUabF.net
調べてみると、Python のラムダ式で任意の文が書けないという問題(>>191)は、
過去に何度もネット上で話題になっていたようだね:
・Is it possible to have multiple statements in a python lambda expression? - Stack Overflow (May 14 '09)
 URLリンク(stackoverflow.com)
・syntax - No Multiline Lambda in Python: Why not? - Stack Overflow (Aug 5 '09)
 URLリンク(stackoverflow.com)
・Why doesn't Python allow multi-line lambdas? - Programmers Stack Exchange (Aug 7 '11)
 URLリンク(programmers.stackexchange.com)

そして、この問題を解決すべく数多くの提案が出された:
・AlternateLambdaSyntax - Python Wiki
 URLリンク(wiki.python.org)

それら提案の中には、Ruby のブロックを真似しよう(similar to Ruby's blocks)、というものまであった
・[Python-ideas] Proposal for function expressions - Grokbase
 URLリンク(grokbase.com)

しかし残念ながら、これ以上続けても収束しそうもないから議論は打ち切り、とGuido氏が宣言(強権発動?)して終わった
・[Python-Dev] Let's just *keep* lambda
 URLリンク(mail.python.org)
この顛末をGuido氏は「複数行のラムダは解けないパズル(unsolvable puzzle)」と語っている
・Language Design Is Not Just Solving Puzzles
 URLリンク(www.artima.com)

まさに「みんなを納得させるほどの「結論」じゃない」というのは、こういう状況を指しているんだろね....
 スレリンク(tech板:9番)

200:デフォルトの名無しさん
14/12/11 22:55:21.60 aWaBOmKM.net
>>191
普段Python書かないからPythonicではないかもしれないが、だいたいこんな感じだろう。
URLリンク(ideone.com)

それで、何が問題なんだ?

201:デフォルトの名無しさん
14/12/11 23:02:23.22 GpAyUabF.net
>>198
ではクロージャ定義の引用元ソースを示そうね

答えは書籍「計算機プログラムの構造と解釈」、いわゆるSICP本だ
その中の節「3.2.1 評価の規則」に手続きオブジェクトが、いわゆるクロージャに対応する
 URLリンク(sicp.iijlab.net)

そしてクロージャを視覚化したのが、
このページの図3.2にあるオタマジャクシの卵が2つ並んだ図形になる

単純な話だと思うけど、難しいかな?

202:デフォルトの名無しさん
14/12/11 23:27:50.83 GpAyUabF.net
>>200
関数を宣言せずに書くという制約の元ですから、とてもPythonらしいコードだと思います
しかもループの代わりに関数再帰を使っているのですから、より関数型プログラミングらしいとも言えます

ただし、元々 Swift で書かれていたサンプルコードを各 LL へと書き直しているのですから、
もし以下の点を改善できれば(Pythonらしさという意味では)完璧でしょう:
・中間変数 f を宣言せず、リスト内包式の中にラムダ式をインラインで書く
・Swift のコードは辞書を使っているのですから、それを(勝手に)配列 digits へ改変せず、
 Python でも(Ruby や JavaScript と同様に)辞書を使って書く

203:デフォルトの名無しさん
14/12/12 00:10:51.51 kNbqUbaQ.net
>>202
注文が多いな。
URLリンク(ideone.com)

204:デフォルトの名無しさん
14/12/12 09:01:50.64 hLblKLHb.net
>>201
で、どこに「クロージャは無名関数でなければダメ」と書いてあるの?
「Schemeという特定の言語」で「クロージャはlambda式で作られる」と書いてあるだけだが?

いい加減、誤摩化して逃げ回るのは止めたら?

205:デフォルトの名無しさん
14/12/12 18:43:57.39 JZfpq2Ndq
以前も書いたけどPythonistaは走り書き以外でlambdaなんて使わないから。

206:デフォルトの名無しさん
14/12/12 19:05:12.73 1wfis/cT.net
別にPythonのラムダに式が書けないから問題だと言うだけなら荒れねーよ
そこで「だからPythonにはクロージャが無い」って言う
決して成り立たない等式を持ち込むから「いやそのりくつはおかしい」って言われてんのに
そしたら既存のクロージャという用語の定義のほうを弄ろうとするから叩かれてんだろうが

プログラミングに例えるなら、お前は自分の書いた関数で
組み込み整数型の値にそのままリスト処理を適用しようとして例外吐かれたから、と
整数クラスのほうがリストとして振る舞うようにメソッドを書き換えようとしてる

207:デフォルトの名無しさん
14/12/12 22:20:24.14 ZYnyJXBo.net
>>203
お疲れさまです
中間変数 f は消えましたが、今度は中間変数 applyf が現れてしまいましたね....

208:デフォルトの名無しさん
14/12/12 22:38:08.46 hhr7pvhS.net
>>207
URLリンク(ideone.com)

209:デフォルトの名無しさん
14/12/12 22:42:02.66 hLblKLHb.net
>>207
とりあえずクロージャの定義を貼っておきますね
反論よろしく

URLリンク(www.princeton.edu)(computer_science).html


> In computer science, a closure is a first-class function with free variables that are bound in the lexical environment.


ここの文章も良く読んでね

> The term closure is often mistakenly used to mean anonymous function.
> This is probably because most languages implementing anonymous functions allow them
> to form closures and programmers are usually introduced to both concepts at the same time.
> These are, however, distinct concepts.

210:デフォルトの名無しさん
14/12/12 23:33:45.85 ZYnyJXBo.net
>>204
> で、どこに「クロージャは無名関数でなければダメ」と書いてあるの?

もちろん「クロージャは無名関数でなければダメ」とは書かれていない
同時に「ラムダ式に文が書かなくともクロージャである」とも書かれていない
SICP本を理解するには、記述されている定義から類推によって解釈できる知性が必要だね


>「Schemeという特定の言語」で「クロージャはlambda式で作られる」と書いてあるだけだが?

この節で記述されているのはクロージャの一般的な概念であり、特定の言語や実装には限定されない
ここで記述されている概念に沿って設計された言語であれば、たとえば:
・Scheme なら (lambda (x) .... ) で、
・Standard ML なら fn x => .... で、
・JavaScript なら function(x) { ..... } で、
・Ruby なら proc { |x| .... } で作られる
ここで.... の部分には、破壊的代入や入出力等の副作用を伴う任意のコードが書ける
唯一、書けないのは Python だけ

で、どこに「Schemeという特定の言語」と書いてあるの?
いい加減、誤摩化して言い逃れをするのは止めたら?

211:デフォルトの名無しさん
14/12/12 23:54:36.75 ZYnyJXBo.net
>>208
ありがとうございます、これで完璧ですね

これで「何が問題なんだ?(>>200)」という議論を続けることができます
具体的には、>>191 の Swift/Ruby/JavaScript で書かれたコードと
>>208 の Python で書かれたコードを比較して、
「どちらがわかりやすいか/読みやすいか/書きやすいか?」という話です

で、これらは主観による評価ですから、
いくら議論しても誰もが納得できる結論へとは収束しないでしょう
すべての Pythonista にとって >>208 が読みやすく書きやすいと感じるのなら、
それはそれでいいんじゃないでしょうか

212:デフォルトの名無しさん
14/12/13 00:01:46.30 HrrHquek.net
一時変数を消すためにそんなパズルみたいな事やって読みやすいわけないだろw

213:デフォルトの名無しさん
14/12/13 00:13:09.40 HrrHquek.net
>>210
schemeではlambdaが本質的なもので(define (f x) ~)はシンタックスシュガーだけど、
pythonではdefが本質的なものでlambdaの方がシンタックスシュガーなのでは。

214:デフォルトの名無しさん
14/12/13 00:39:02.24 gzcIElev.net
>>209
Wikipedia 英語版の解説と同じに見えるけど、何を言いたいのかな?
・Closure (computer programming) - Wikipedia, the free encyclopedia
 URLリンク(en.wikipedia.org)(computer_programming)
単に他人の文書をコピペして終わりにするだけでなく、引用した文書(ソース)を元に、
自分なりの意見を思考しそれを自分の文章として表現できるようになったほうがいいと思う


で、とりあえず反論しておくと、その文書(= Wikipedia)の
章「mplementation and theory」には、冒頭に以下の記述がある

> Closures are typically implemented with a special data structure that
> contains a pointer to the function code, plus a representation of
> the function's lexical environment (i.e., the set of available variables)
> at the time when the closure was created.

この理論としてのクロージャ定義は、SICP本(>>121) および >>4 のそれと矛盾していない
そして Haskell のような純粋関数型言語に限定した文脈ではないのだから、
文中の "function code" は(>>210 で書いたように)単なる式だけではなく
破壊的代入や入出力等の副作用を伴う任意のコードも書けると解釈するのが自然だと考える

215:デフォルトの名無しさん
14/12/13 02:01:28.39 6/3yjF6w.net
>>4
>クロージャを識別子に束縛したものが一般的な「関数宣言」である

よかった、pythonにもちゃんとクロージャあった

216:デフォルトの名無しさん
14/12/13 02:13:23.84 6/3yjF6w.net
foo = lambda bar: bar
これはクロージャである

っていうのが偽であることを定義から証明すればいいんじゃないかな
反例あげればいいだけだよね?

217:デフォルトの名無しさん
14/12/13 02:17:02.89 6/3yjF6w.net
あ、まちがえたそれはクロージャじゃない
def foo():
bar = 1

これに訂正

218:デフォルトの名無しさん
14/12/13 07:14:46.97 toJAZvUP.net
>>211
それはPythonの書き方じゃないんだよ。
お前が>>202で指定したから、結果的にそうなっただけで。

それで、結局「クロージャを書けない」から「読みにくい」に問題をすり替えて終わりか?

219:デフォルトの名無しさん
14/12/13 08:00:50.00 1EyzOdES.net
URLリンク(ideone.com)

220:デフォルトの名無しさん
14/12/13 10:42:15.83 ygYpq94K.net
イデオンこわい

221:名無しさん@そうだ選挙に行こう
14/12/13 12:26:47.45 sGDpUYPr.net
>>210
> もちろん「クロージャは無名関数でなければダメ」とは書かれていない

なんだ、Pythonのdefで良かったんだ

知らないみたいだから教えてあげるけど、Pythonではdefで関数定義すると
環境を持ったクロージャになってるんだよ、勉強になったね

222:名無しさん@そうだ選挙に行こう
14/12/13 12:40:53.92 sGDpUYPr.net
>>211
>>203のapplyfは、特定のロジックに依存しない汎用的な関数だけど、
こういうものの定義や使用も認めないってことは
ライブラリによる拡張も否定するってことでOK?

ライブラリを使わないと外部イテレータが使えないRubyをdisってるの?

223:名無しさん@そうだ選挙に行こう
14/12/13 14:05:13.26 ZLG0O37u.net
>>210
書かれてない要素を勝手に追加するから
オレオレ定義って言われるんだよ

クロージャの定義には無名関数であることも、文が書けるor書けないことも、
含まれてないんたから、勝手に条件に追加すんな

224:名無しさん@そうだ選挙に行こう
14/12/13 14:39:36.41 1EyzOdES.net
>>220
>>219 はPythonのlambdaからでも副作用を伴うメソッド呼べますよってコードだな

225:名無しさん@そうだ選挙に行こう
14/12/13 20:13:18.59 gzcIElev.net
>>213
本質という言葉の定義が曖昧ですが、自分なりにコメントします

まず >>209(= Wikipedia, >>214)の章「2.1 First-class functions」には、
その冒頭に以下の記述があります

> Closures typically appear in languages in which functions are first-class values ―
> in other words, such languages enable functions to be passed as arguments,
> returned from function calls, bound to variable names, etc.,
> just like simpler types such as strings and integers.

つまりクロージャは「一級の値( first-class values)」であると定義しています
従って(一級市民ではない関数宣言 def よりも)一級市民であるクロージャ lambda を
本質とするのが正しいのではないかと思います
(「宣言された関数は一級市民だけど、宣言そのものはそうではない」という意味です、念の為)

(あくまで私見ですが)可能性があるのは、関数スコープ方式の手続き型言語である Python では、
関数型言語の特性を追加する際にクロージャを(lamda ではなく)宣言された関数へ実装したほうが
(開発工数や難易度の視点からは)容易だったのではないかと推測します(詳細は省略....)
一言で言えば「Python は手続き型言語だから」ということですね

226:名無しさん@そうだ選挙に行こう
14/12/13 20:39:14.11 HrrHquek.net
>>225
本質的ってのは、よりプリミティブなものっていう意味で書いたんだよ。

first-class valueってのは、変数に代入したり、関数の引数に渡したり、
関数の値として返したりできるオブジェクトの事だよ。
def だの lambda だのっていうのはそういうオブジェクトであるクロージャを作り出すための構文だよ。

pythonは手続き型言語だっていうけど、そんなの当たり前だろw
rubyだのjavascriptだのだって手続型言語だよ。

227:名無しさん@そうだ選挙に行こう
14/12/13 21:42:39.17 gzcIElev.net
>>226
> 本質的ってのは、よりプリミティブなものっていう意味で書いたんだよ。

その意味であれば、関数型言語と Ruby/JavaScript だと
関数定義よりもクロージャのほうがが本質的だね
プリミティブな名前とクロージャから関数(or メソッド)が作られるという
因果関係があるのだから

ただし、Python だけは違うみたいだね


> rubyだのjavascriptだのだって手続型言語だよ。

外見は手続き型言語だけど、どちらの言語もLISPをベースに設計されている
だから最初から関数型言語と同等なクロージャを備えて誕生した
それが知られるようになったのは最近だから、知らない人は多いけどね.....
手続き型言語として生まれ、後付けで関数型を増築した Python とは違うのだよ
 スレリンク(tech板:857番)

--
> パクリどころか Ruby と JavaScript は、これらの作者自身が
> Lisp を基礎として言語を設計したと語っている
>
> ・Lisp から Ruby への設計ステップ
>  URLリンク(yohshiy.blog.fc2.com)
> ・JavaScript: The World's Most Misunderstood Programming Language
>  URLリンク(www.crockford.com)
> (邦訳版「JavaScriptの勉強:世界で最も誤解されたプログラミング言語」へのリンクは閉鎖)
>
> だから関数型プログラミングという土俵の上で Ruby や JavaScript に
> 手続き型言語の Python がいくら挑戦しても勝てずに負け続けているのは、
> しごく当然な結果なわけ

228:名無しさん@そうだ選挙に行こう
14/12/13 22:07:55.30 HrrHquek.net
>外見は手続き型言語だけど、どちらの言語もLISPをベースに設計されている

S式で表現されてなきゃlispじゃねえよ。

229:名無しさん@そうだ選挙に行こう
14/12/13 22:14:57.19 HrrHquek.net
だいたいlispが関数型言語だって言うことにも抵抗がある。

230:名無しさん@そうだ選挙に行こう
14/12/13 23:06:18.71 gzcIElev.net
>>227
>手続き型言語として生まれ、後付けで関数型を増築した Python とは違うのだよ

自己レスで補足する(すべての手続き型言語が Python と同じではない....

同じ手続き型言語に関数型の特性を追加した言語でも、
調べた範囲だと少なくとも Perl5/Java8/C++11 のクロージャは
>>4,>>121 のクロージャ定義に沿って設計され、
・クロージャ内で任意の文が書ける
ただしそれら言語がクロージャをサポートした時期は遅かった
真面目に設計したからだろう

対して Python の関数型サポートは素早かったけど、検討が不十分だったと言うほかない
リリース後に改善要望/議論紛糾したあげく、結論を出せず現在に到る(>>199)

231:名無しさん@そうだ選挙に行こう
14/12/13 23:27:26.05 fdPKe7oz.net
横だけど、
Rubyのブロックはラムダじゃないしファーストクラスでもないよね

メソッドにラムダを渡すこともできるけど、不格好なんだが?
これって、ここのオレオレ定義にてらすとどうなの?

なんだか、ラムダに文を書けない(書かない)ようにしている
Pythonの仕様をあげつらうためだけにオレオレ定義をこねくって
悦に入ってるPythonアンチがいるって感じがするだけなんだが。

232:デフォルトの名無しさん
14/12/14 00:01:22.20 Gw1grNBM.net
Rubyのブロックの中に副作用をジャンジャン書いて
それを繋げるスタイルを関数型と言われても困るわ

文推奨の時点で関数型とは言い難いわけだし

233:デフォルトの名無しさん
14/12/14 00:38:38.65 iRnVJ1/v.net
オレオレクロージャ君は言葉が通じないし、
必死でググった的外れで糞長い引用でしか反応しないし、
相手するだけ無駄。

234:デフォルトの名無しさん
14/12/14 02:05:45.83 sl2oQCLD.net
うん、ただのPythonアンチでしか無いと思うよ。
Ruby好きでPython嫌いな俺は、Pythonのlambdaが使いにくいのには同意するが
そのためにクロージャの定義のほうを捻じ曲げるのは、ありえないと感じるよ。
そもそも、その定義だとRubyどーなんねん、と思うし。

Rubyには「他言語の関数」に相当するものがなく、
一定の条件を満たし、見かけ上、関数のような呼び出しが可能なメソッドを
便宜的に「関数」と呼んでいるだけだし。

クロージャはブロックという形で存在はしているが、
彼の言う定義に従うならブロックはファーストクラスでなければならない。
でもRubyのブロックはファーストクラスとは言い難い。
lambda関数(実際はもちろんメソッド)が返すのはProcクラスのインスタンスだけれども、
ブロック.is_a? Procインスタンス では無い。そしてメソッドや、ましてや関数でもない。
そもそもブロック単体では値としては取り回せないからProcクラスがあるんだし。

235:名無しさん@そうだ選挙に行こう
14/12/14 10:29:16.99 63H3dBz7.net
オレオレクロージャ君って少し前に某スレでPython disってた人にそっくり

236:名無しさん@そうだ選挙に行こう
14/12/14 14:05:17.21 2A/iPobJ.net
lambda

ラ…ランバダ…

237:名無しさん@そうだ選挙に行こう
14/12/14 14:52:29.83 VBy2GaOL.net
>>236
もっと勇気をもって!
ランバダ!

238:名無しさん@そうだ選挙に行こう
14/12/14 15:49:06.80 hNeAViIY.net
       ,-----、
      /     ヽ.
      | (・) (・) |
  /ヽ ̄       ̄ノヽ
 /   ヽ_____/  ヽ
 |   /    l   |    |\
 |   |  。ノ ヽ。 .|___|  \
 ヽ___ヽ    +   ノ,、_、_、_ヽ  \
  |  ヽ| ̄ ̄ ̄ ̄ | ;;;;;;;;;;;;;;;\_ ノ
 < ````/\     /\;;;;;;;;;;;;;;;;;/
  ヽ;;;;;;|  \_/   ヽ;;;;;;;;;;;ノ
    ̄.|___/   \__) ̄   .____
    /   |     |   |    \ /
   (___|     |__)===⊃

      勇者の父 ランバダ

239:名無しさん@そうだ選挙に行こう
14/12/14 15:54:41.51 KqwrXZGg.net
無駄にMP消費していざという時に足りなくなって犬死にする無能

240:デフォルトの名無しさん
14/12/14 20:48:34.17 lkA9lgpO.net
>>231
>Rubyのブロックはラムダじゃないしファーストクラスでもないよね?

Python や JavaScript のクロージャは、(名前が宣言された)関数と同様に
クロージャへ引数を渡すだけで評価される
  closure = function(x) { return x + 1 }  # クロージャを生成して名前に束縛
  succ_of_one = closure(1)  # クロージャを評価
それに対して Ruby だと、メソッド Proc#call を呼ばなければ評価されない
  block = lambda { |x| x + 1 }  # ブロックを生成して名前に束縛
  succ_of_1 = block.call(1)  # ブロックを評価
従って >>4(>>201) の関数型言語におけるクロージャ定義に当てはめれば
「Ruby のブロックは(本物の)クロージャではない」あるいは「....はクロージャもどきである」
またRuby のブロックの意味はオブジェクト(Procクラスのインスタンス)だからファーストクラスである

>メソッドにラムダを渡すこともできるけど、不格好なんだが?

たしかに不格好だ
 def foo(x, y, &block); .... ; end  # メソッドを定義
 foo(x, y, lambda { |z| .... })  # メソッドの呼び出し
だから Ruby には「ブロック付きメソッド呼び出し」という構文糖が最初から用意されている
 def foo(x, y); .... ; end  # メソッドを定義
 foo(x, y) { |z| .... }  # メソッドの呼び出し

>Pythonの仕様をあげつらうためだけにオレオレ定義をこねくって

>>4 のクロージャ定義の引用元(ソース)は >>201 で示したが、まともな反論はない
むしろオレオレ定義と騒ぎ立てていた連中がSICP本を読んだ事もないお馬鹿達だったのでは?
あるいはSICP本を読んでいなくても、関数型言語の操作的意味論や処理系実装の知識があれば
>>4 がオレオレ定義でないことは直ぐに理解できていたはず

241:デフォルトの名無しさん
14/12/14 21:10:51.70 Gw1grNBM.net
>>240

後から言い逃れようとしても、掲示板にはログが残ってるから無駄ですよ
>>99に対する>>103の返答の時点で、何も分かってなかったのは明らか

242:デフォルトの名無しさん
14/12/14 21:42:31.25 k3gK/GUJ.net
>>240
RubyのブロックはProcクラスのインスタンスではないよ
ブロックそのものは、メソッド呼び出し文法の一部でしかない
そのブロックを、それのみで値として扱うためのラッパがProc

243:デフォルトの名無しさん
14/12/14 21:59:53.72 Y1wljoB2.net
Rubyistは全員クロージャを間違った解釈してるのか?
それとも、奴だけなのか?

そこが気になるな。

244:デフォルトの名無しさん
14/12/14 22:03:54.59 lkA9lgpO.net
>>232
残念ながら Ruby の関数型プログラミングというスタイルは、
全世界の Ruby コミュニティですでに認知されている
・Functional programming with Ruby
 URLリンク(code.google.com) 
・Rubyによる関数型プログラミング(上記文書の日本語訳)
 www.h6.dion.ne.jp/~machan/misc/FPwithRuby.html
また Ruby の「ブロック付きメソッド呼び出し」とそれらを並べる(=チェーンさせる)スタイルは、
Apple の新言語である Swift にそのまま採用された
他の言語、たとえばラムダ式が導入された Java 8 だと、このスタイルをストリームと呼んでいる
・ラムダ式で本領を発揮する関数型インターフェースとStream APIの基礎知識 (2/3) -- @IT
 URLリンク(www.atmarkit.co.jp)

個人的には、Ruby と多くのOOP言語で採用されているメソッドチェーン・スタイルは:
・データの流れ(いわゆるデータフロー)とメソッドの並びが一致し、
・カッコが入れ子にならない
から、可読性が高いと思う
 table.select { |r| .... }.map { |r| .... }.inject(0) { |n, r| .... }  # >>191 を参照
それに対して、Python 伝統的な関数適用スタイルでは:
・データの流れ(いわゆるデータフロー)とメソッドの並びが逆転し、
・カッコが入れ子になる
 reduce(lambda n, r: ...., 0, map(lambda r: ...., filter(lambda r: ...., table)))
どちらを優れているか?という評価は主観だから、各自で判断してもらいたい


(まだ続くので、ここで切る)

245:デフォルトの名無しさん
14/12/14 22:48:49.10 lkA9lgpO.net
>>241
次に、関数型プログラミングと(文の評価によって起こる)副作用との関連について

まず関数型プログラミングで副作用は推奨されていない
基本的には map/filter/reduce (Ruby では map/select/inject) といった高階関数を使った
(副作用の無い)参照透明性のあるコードが推奨されている
これは >>244 の文書「Rubyによる関数型プログラミング」で具体的なコード例を使って解説されている

おそらく誤解したのは >>191 の Swift/Ruby/JavaScript コードで while 文と
ローカル変数への破壊的代入を用いていたのを見たからだと思うけど、
これは、「わざわざ」副作用を使った手続き型プログラミングほうが簡潔になる「お題」を選んだからだ
実際、副作用の代わりに再帰を使った Python コード >>208 は「普通のプログラマ」には分かりにくい
(Python だけでなく、この「お題」は Ruby であっても再帰を使えば同じく分かりにくいコードになる)

また(Ruby を含む)大半の手続き型言語処理系だと、TCO(末尾再帰最適化)は実装されていないか不完全である
だから手続き型言語における関数型プログラミングにおいて、
再帰プログラミングには(分かりづらいだけでなく)実用上の制限があるから
ツリーのような再帰的データ構造の探索問題などに限定して利用すべき(上記文書の節「再帰」を参照)

これらの判断について、上記の文書では以下のように記述されている(節「おわりに」から引用):
 「Rubyは基本的には命令型言語であるけれど、 関数型プログラミングへの際立った潜在能力があるのだから、
  それらをいつどのように使うか(そして、いつ使わないか)を知っておくべきである。 」

246:デフォルトの名無しさん
14/12/14 22:59:19.75 iRnVJ1/v.net
もうみんなgaucheに改宗しようぜ

247:デフォルトの名無しさん
14/12/14 23:34:55.92 lkA9lgpO.net
>>234
>Rubyには「他言語の関数」に相当するものがなく、......

これは(>>240 に書いたけど)、まったくそのとおり


>でもRubyのブロックはファーストクラスとは言い難い。

ここの「....とは言い難い」という文章表現は曖昧だね
(なぜ「....ではない」と断定的に言い切れなかったのだろうか?)

まず >>240 で書いたように、Ruby の「ブロック付きメソッド呼び出し」は構文糖だ
(対して、簡潔な構文を追求した Smalltalk では、常にブロックはオブジェクトである)
これを構文糖にした理由の一つはメソッド呼び出しコードを簡潔にする目的(>>240)であるが、
ブロックを多用する Ruby のプログラミングスタイルでは、ブロックを評価するたびに
Procオブジェクトを生成していたのでは実行効率の面でオーバヘッドが大きいという理由がある
このためRubyインタプリタの内部だと、
ブロックは(重いオブジェクトを表すC構造体ではなく)専用の軽量なC構造体で表現されている

ただし、(たとえ内部表現が Proc オブジェクトと異なっていても)プログラマから見れば問題にならない
なぜなら、渡されたブロックをいつでも Proc オブジェクトへ変換できる構文糖が最初から用意されているから....
たとえば foo(x, y) { |z| .... } という「ブロック付きメソッド呼び出し」に対して(>>240):
・def foo(x, y); .... ; end
・def foo(x, y, &block); .... ; end
 という2つのメソッド定義は「いつでも」交換できる

まとめると:
 Ruby のブロックは内部表現だと Proc オブジェクトではないが、
 プログラマ目線ではファーストクラスのオブジェクトとして扱うことができる

248:デフォルトの名無しさん
14/12/14 23:42:14.32 NejhiS1a.net
gaucheいいよね

249:デフォルトの名無しさん
14/12/14 23:49:27.85 lkA9lgpO.net
>>241
つまり「Ruby のブロックはクロージャである」という初歩的なミスについて、
>>103 をレスした時点から数えて >>231 が指摘するまでの間には
誰一人気付けなかった事実が「掲示板にはログが残ってるから明らか」になるわけですね



た い へ ん わ か り や す い で す

250:デフォルトの名無しさん
14/12/14 23:57:54.55 pRYhwT4i.net
最近はほぼgaucheでしかプログラム書いてない。
もう止められない体になってしまった。。。

251:デフォルトの名無しさん
14/12/14 23:58:44.82 iRnVJ1/v.net
俺、numpyとscipyとopencvのサポートがgaucheにくっ付いたら、python捨てるんだ!(遠い目

252:デフォルトの名無しさん
14/12/15 00:02:02.47 wtT+wvpm.net
common lisp処理系の方が速いのあるしライブラリも充実してるし良いよ

253:デフォルトの名無しさん
14/12/15 00:07:51.10 G9R+2lJx.net
ループしないで全部再帰で書きたい

254:デフォルトの名無しさん
14/12/15 00:08:50.51 YlFhPVoF.net
lisp-2なのが何となく嫌

255:デフォルトの名無しさん
14/12/15 00:31:53.12 K7E8QpHY.net
>>253 いいよ

256:デフォルトの名無しさん
14/12/15 08:42:12.40 J0ddkTzC.net
>>249
だってRubyなんてマイナー言語どうでも良いし?

257:デフォルトの名無しさん
14/12/15 11:24:34.16 yMEZ5G45.net
>>243
こいつだけです。と言うかRubyに対しての知見も怪しい

>>247
Rubyのブロック付きメソッド呼び出しのほうを構文糖と。またオレオレ定義?
「ブロック付きメソッド呼び出し」は文法だ、これはlambdaより先に実装されてる
そのブロック部分のみを扱うためにProcクラスもlambdaより先に実装されていて、
そのProcを簡便に扱うためにlambdaと言う構文糖が後から出来た

と言うか「ブロック付きメソッド呼び出し」、昔は「イテレータ呼び出し」だった
イテレータ呼び出しを汎化した結果生まれたのが、ブロック付きメソッド呼び出し
その時代からmapやselectなどの
今で言う関数型的なメソッド群を実装するモジュールEnumerableは
「これをincludeするクラスにはeachメソッドを実装すること」としていた

もしRubyが関数型として設計されていてProcが主なら
call必須なんてことにはしなかっただろうし
関数がメソッドの一種なんてことにはなってない
そしてEnumerableはeachではなく、Array辺りを要求する高階関数群だっただろう
RubyはOOPLとして設計され、それが主で
関数型プログラミングは結果として付いてきた
そこでProcに関数型のラムダ的な挙動を付加し生成するlambdaも出来たんだよ

258:デフォルトの名無しさん
14/12/15 20:13:34.89 AoWRRy2d.net
>>244
> また Ruby の「ブロック付きメソッド呼び出し」とそれらを並べる(=チェーンさせる)スタイルは、
> Apple の新言語である Swift にそのまま採用された
Obj-C が inline Smalltalk が書ける C なのに、Swift が Ruby をまねたみたいなデマはやめてくれる?

それと、 Ruby で関数型スタイルのプログラムを書けるということを、Ruby で書いたら関数型プログラムになるかのように書くのもやめてくれる?


次ページ
最新レス表示
レスジャンプ
類似スレ一覧
スレッドの検索
話題のニュース
おまかせリスト
オプション
しおりを挟む
スレッドに書込
スレッドの一覧
暇つぶし2ch