言語を選ぶ基準

私が実際に使ってもいいかなと思う言語の基準というのはいろいろあるのですけど、重視している基準に次のプログラムが書けるか、というのがあります。
それは、schemeで書くと次のプログラムです。

(define (f x)
  (define (g y) (+ x y))
  (define (h x) (g 10))
  h)

((f 10) 1) ;; => 20

他の言語を見てみると、Pythonなら次のようになりOK。

def f (x):
  def g (y): return x + y
  def h (x): return g(10)
  return h

f(10)(1) # => 20

Cleanも当然OK

f x = h
  where
    g y = x + y
    h x = g 10

Start = f 10 1 // => 20

Ocamlも当然OK

# let f x
    = let g y = x + y in
      let h x = g 10 in
      h;;
val f : int -> 'a -> int = <fun>
# f 10 1;;
- : int = 20

Javaは関数がないですが、クラスが代わりに使えます。どう贔屓目に見ても、簡潔さに欠けますが。

public class Main{
  static abstract class Fn{ abstract int $(int i);}
  static Fn f (final int x){
    final Fn g = new Fn(){ int $(int y){ return x + y;}};
    final Fn h = new Fn(){ int $(int x){ return g.$(10);}};
    return h;
  }
  public
  static void main(String[] args){
    System.out.println(f(10).$(1)); // => 20
  }
}

JavaScriptもOK

function f (x){
  function g (y){ return x + y;}
  function h (x){ return g(10);}
  return h;
}

f(10)(1); // => 20

他の言語はどうなんでしょう?

      • -

ちなみに、私はいつもRubyでこれをやろうとしてよくわからなくなって止めてしまうのです・・・
とりあえず、次のはだめ。

irb(main):001:0> def f (x)
irb(main):002:1>   def g (y) x + y end
irb(main):003:1>   def h (x) g(10) end
irb(main):004:1>   h
irb(main):005:1> end
=> nil
irb(main):006:0> f(10)(1)
SyntaxError: compile error
(irb):6: syntax error, unexpected '(', expecting $end
f(10)(1)
      ^
        from (irb):6
        from :0
irb(main):007:0> f(10)
ArgumentError: wrong number of arguments (0 for 1)
        from (irb):4:in `h'
        from (irb):4:in `f'
        from (irb):7
        from :0

こう書くとまた別のエラーに。

irb(main):001:0> def f (x)
irb(main):002:1>   def g (y) x + y end
irb(main):003:1>   Proc.new {|x| g(10)}
irb(main):004:1> end
=> nil
irb(main):005:0> f(10).call(1)
NameError: undefined local variable or method `x' for main:Object
        from (irb):2:in `g'
        from (irb):3:in `f'
        from (irb):5
        from :0

そして、次のはうまく行きそうなのですが、よくわからない結果に。

irb(main):001:0> def f (x)
irb(main):002:1>   g = Proc.new {|y| x + y}
irb(main):003:1>   h = Proc.new {|x| g.call(10)}
irb(main):004:1>   h
irb(main):005:1> end
=> nil
irb(main):006:0> f(10).call(1)
=> 11