トップページ⇒tech
1001コメント388KB

【激突】関数型言語 VS オブジェクト指向言語2

■ このスレッドは過去ログ倉庫に格納されています
0001営利利用に関するLR審議中@詳細は自治スレへ2012/04/07(土) 21:26:47.61
一般的には、オブジェクト指向型言語が優勢でが
一部には関数型言語を崇拝している人もいます

どちらが上なのか、この際はっきりさせましょう

前スレ http://toro.2ch.net/test/read.cgi/tech/1331328955/
0507デフォルトの名無しさん2012/04/19(木) 13:20:53.20
>>504
それは基本的にStateモナドの領域。
Readerモナドの中で、さらにサブルーチン的に他のReaderモナドを呼び出す時に、
一時的に書き換えたように見せかけたい、っていう場合ならばlocal関数が使えるけど。

Readerモナドで更新したいって、読み取り専用変数に書き込みたいって言ってるのと同じ事なのはわかってるよな…?
0508デフォルトの名無しさん2012/04/19(木) 17:54:57.76
Reader
(s -> a) -> (a -> s -> b) -> s -> b
Writer
(a,s) -> (a -> (b,s)) -> (b,s)
State
(s -> (a,s)) -> (a -> s -> (b,s)) -> s -> (b,s)
0509デフォルトの名無しさん2012/04/20(金) 11:54:43.80
>>500
あるときは a
またあるときは m a
m a -> (a -> m b) -> m b
0510デフォルトの名無しさん2012/04/20(金) 17:52:20.76
なんつーか、FizzBuzzしたいんならHQ9F+使えばいんじゃね?
0511デフォルトの名無しさん2012/04/20(金) 22:29:27.34
お題出していい?
0512デフォルトの名無しさん2012/04/20(金) 22:55:07.28
・コンソール上で動く、カード(つーてもただの数字を表示するだけだが)を使ったミニゲーム
・1〜9のカードを各4枚ずつ用意、それをシャッフルして「ストック」とする
・ストックから7枚のカードを引く
・引いたカードの中から、プレイヤーは合計が15になるように数枚を選んで捨てる
(選ばせ方はプログラマが考える、ギブアップ手段も用意)
・捨てなかったカードと合わせて再び7枚になるか、もしくはストックが空になるまでストックからカードを引く
・また15になるように捨てる
・引いては捨ててを繰り返し、ストックと手札が共に空になったらおめでとう的な言葉を吐いて終了
0513デフォルトの名無しさん2012/04/20(金) 23:16:37.51
つまらない。
0514デフォルトの名無しさん2012/04/21(土) 01:27:35.30
>>512
Squeak Smalltalk で。

| ui stock player |
ui := UIManager default.
stock := (1 to: 9) gather: [:each | Array new: 4 withAll: each].
stock := stock shuffled asOrderedCollection.
player := (stock removeFirst: 7) asOrderedCollection.
[ | choice |
   [ | input |
      input := ui request: player asSortedArray asString, 'から合計が15になるようにチョイス'.
      choice := input subStrings collect: #asInteger.
      choice ifEmpty: [(ui confirm: 'ギブアップ?')
         ifTrue: [^self] ifFalse: [choice := {nil}]].
      (choice allSatisfy: #isInteger)
         and: [choice sum = 15]
         and: (player includesAllOf: choice)
         and: [choice asSet allSatisfy: [:card | (player occurrencesOf: card) >= (choice occurrencesOf: card)]]
   ] whileFalse.
   player removeAll: choice.
   player addAll: (stock removeFirst: (choice size min: stock size)).
   player notEmpty] whileTrue.
ui inform: 'おめでとう!'
0515デフォルトの名無しさん2012/04/21(土) 02:46:31.71
>>514
なぜこの人は今どきSmalltalkの末裔を使っているのか理由をうかがいたいので
おしえてくださいです
0516デフォルトの名無しさん2012/04/22(日) 01:52:01.88
# Ruby版、指定は半角空白区切り、EOFでギブアップ
class CardNotFoundException < RuntimeError; end
def remove_cards(specs, tableau)
    specs.each do |spec|
        if idx = tableau.find_index{|card| card == spec }
            then tableau.delete_at idx
            else raise CardNotFoundException.new(spec.to_s)
        end
    end
end
stock = ((1..9).to_a * 4).shuffle
tableau = []
until tableau.empty? && stock.empty?
    tableau.push stock.pop until tableau.size >= 7 || stock.empty?
    printf "stock=%d tableau=%p\n? ", stock.size, tableau
    k = gets or exit
    specs = k.chomp.split(' ').map{|s| s == 'giveup' ? exit : s.to_i }
    begin
        remove_cards specs,tableau.dup
        if (total = specs.inject{|result,n| result + n }) == 15
            then remove_cards specs,tableau
            else puts "total(#{total}) not equal to 15"
        end
    rescue CardNotFoundException => e
        puts "not found `#{e}'."
    end
end
puts 'Congraturations !'
0517デフォルトの名無しさん2012/04/22(日) 02:31:25.32
>>514をRubyに翻訳してみた版

stock = ([*1..9]*4).shuffle
player = stock.shift(7)
loop do
  choice = nil
  loop do
    puts player.sort.inspect + "から合計が15になるようにチョイス"
    choice = gets.split(/[, ]/).map(&:to_i)
    choice.delete(0)
    if choice.empty?
      puts "ギブアップ?[Y/n]"
      !(gets=="n\n") ? exit : choice = [0]
    end
    break if choice.all?(&:integer?) and
      choice.reduce(&:+) == 15 and
      choice.uniq.all?{ |card| player.count(card) >= choice.count(card) }
  end
  choice.each{ |e| player.delete_at(player.index(e)) }
  player += stock.shift([choice.size, stock.size].min)
  break if player.empty?
end
puts "おめでとう!"
0518デフォルトの名無しさん2012/04/22(日) 12:27:13.72
Squeakは入れたことあるが(てか今も入ってるけど)何をどうしたらいいのか判らん
>>514 のコードをどこに入力して、どう実行したら動くんだ?
0519デフォルトの名無しさん2012/04/22(日) 17:54:43.65
>>518
1. http://sourceforge.jp/projects/squeak-ja/ から Squeak4.2-ja-all-in-one.zip を入手して展開。
2. 同梱 ReadMe-ja.txt などを参考に手元のOSでなんとか起動までこぎつける。無印VMでも新CogVMでもOK。
3. 「ツール」メニューから「ワークスペース」を選択してスクリプトなどのお試し実行用ウインドウを開く。
4. >>514 の | ui stock player | から ui inform: 'おめでとう!' をコピーして 3 のウインドウにペースト。
5. 改めて alt(Macならcmd)+a やマウスドラッグで全選択してから、alt(同cmd)+d で実行。
6. うまく動作すると入力欄がポップアップするので、そこに数字をでスペースなどで区切ってタイプ。
7. 「了解(s)」ボタンクリック(あるいはリターンキー)で入力決定。以降はこれの繰り返し。空決定でギブアップ。

ざっと調べた感じ最新の日本語化版である 4.2ja にこだわらなくても 3.9以降であれば動作するようです。
ただし公式英語版などでは日本語が化けますので適宜英語などに置き換えてからペーストしてください。
日本語版であってもペースト時にエラーがでるようならそのときの対処も同様です。
0520デフォルトの名無しさん2012/04/22(日) 21:05:31.50
// F#で入出力以外の副作用なし
let rec input hands =
    printfn "合計が15になるように捨てるカードをスペース区切りで指定(ギブアップの場合は指定なし)"
    match System.Console.ReadLine() with
    | "" -> None
    | inp ->
        try
            let discardCount = inp.Split([|' '|]) |> Seq.map int |> Seq.countBy id |> Map.ofSeq
            let handCount = hands |> Seq.countBy id |> Map.ofSeq
            if discardCount |> Map.exists (fun n c -> defaultArg (Map.tryFind n handCount) 0 < c)
                || discardCount |> Map.toSeq |> Seq.sumBy ((<||) (*)) |> (<>) 15 then input hands else
            handCount |> Map.map (fun n c -> c - defaultArg (Map.tryFind n discardCount) 0)
            |> Map.toList |> List.collect (fun (n, c) -> List.replicate c n) |> Some
        with _ -> input hands

let rec play hands stocks =
    if (hands, stocks) = ([], []) then printfn "おめでとう!" else
    let cards = stocks |> Seq.truncate (7 - List.length hands) |> Seq.toList
    let nowHands, nextStocks = hands @ cards, (stocks |> Seq.skip cards.Length |> Seq.toList)
    nowHands |> Seq.sort |> Seq.map string |> String.concat " " |> printf "手札 : %s, "
    printfn "山札の残り枚数 : %d" nextStocks.Length
    match input nowHands with Some nextHands -> play nextHands nextStocks | None -> ()

let random = System.Random()
[for i in 1 .. 9 do yield! List.replicate 4 i] |> List.sortBy (fun _ -> random.Next()) |> play []
0521デフォルトの名無しさん2012/04/23(月) 00:28:55.28
>>519
ありがと。何か前に入れたバージョンでやってみたら「[ | input |」の行の左に「Period or right bracket expected ->」とか出たけど、実行の仕方自体は判ったから色々試してみる。
0522デフォルトの名無しさん2012/04/23(月) 00:33:02.59
ああ、インデントを一旦削って入れ直したら動いたわ。thx
0523デフォルトの名無しさん2012/04/23(月) 07:26:59.30
あ、動的にいたスモールトーカーだ。よろしく!
0524デフォルトの名無しさん2012/04/24(火) 12:35:28.99
日本語でおk
0525デフォルトの名無しさん2012/04/25(水) 13:12:07.32
お題:
コンウェイのライフゲームで、
配列の配列(あるいはリストのリスト)で表わされた格子を受け取り
次世代を返す関数lifeを定義せよ。

life([
[0,1,1,1,0],
[0,1,0,0,0],
[0,0,1,0,0],
[0,0,0,0,0],
[0,0,0,0,0]])

#=> [
[0,1,1,0,0],
[0,1,0,1,0],
[0,0,0,0,0],
[0,0,0,0,0],
[0,0,1,0,0]]

また作成した同関数を用いて、500x500のランダムな状態の格子の
500世代目を算出するのにかかった時間(無理なら、算出可能な
世代数とその時間)を計測して示せ。
0526デフォルトの名無しさん2012/04/25(水) 13:54:49.01
くだらん
0527デフォルトの名無しさん2012/04/25(水) 14:03:57.26
Java8でラムダ式が言語仕様に入るようだね
javaもマルチパラダイム化が進むな

OOPLが関数型言語の特徴の一部を取り込む中
スレタイの通り言語比較した場合
「副作用の有無」が一番重要なんじゃないかと思ったけどどうだろう?
機能を取り込むことはあっても無くすことはしないだろうから

副作用の有無が、開発速度や可読性、保守性にどのように影響してくるか・・・

と考えても良いお題は思いつかないんだけどね
0528デフォルトの名無しさん2012/04/25(水) 15:26:58.18
Javaって今でも組み込み型以外は参照型でしか扱えないの?
関数型言語使うようになってから、nullを持たない参照型とか、イミュータブルな値型がいかに重要か思い知った。
しかも、イミュータブルな値型を基本として、nullを持った参照オブジェクト型、nullを持たない参照オブジェクト型って形で扱えないと厳しい。
これは言語仕様として取り込まれていないとどうしようもない。
そういう意味では、C++は結構惜しいところまで行ってたと思う。
0529デフォルトの名無しさん2012/04/25(水) 16:37:33.03
C++にはpure virtual function callというのがあって、仮想関数がnullを持つ。
値型でも仮想関数があったら元も子もない。
仮想関数をやめてswitchを使う覚悟がないと厳しい。
関数型言語のパターンマッチはswitchと同じ方式だ。
0530デフォルトの名無しさん2012/04/25(水) 16:43:26.43
>>528 関数型言語はむしろ全てが参照型とも言えるんだが
0531デフォルトの名無しさん2012/04/25(水) 17:35:29.26
>>525
Squeak Smalltalk (4.2-ja w/CogVM), 1.8GHz Core i7で5分弱。

life := [:ary2d |
   | sum survivs |
   sum := ary2d * 0.
   #(-1 0 1) do: [:dx | #(-1 0 1) do: [:dy |
      sum := sum + ((ary2d collect: [:row | row flipRotated: dx*2]) flipRotated: dy*2)]].
   survivs := #(3 4) collect: [:alive |
      sum collect: [:row | row collect: [:cell | (cell = alive) asBit]]].
   survivs first + (survivs second * ary2d)].

life value: #(
   (0 1 1 1 0)
   (0 1 0 0 0)
   (0 0 1 0 0)
   (0 0 0 0 0)
   (0 0 0 0 0)).

"=> #(
   (0 1 1 0 0)
   (0 1 0 1 0)
   (0 0 0 0 0)
   (0 0 0 0 0)
   (0 0 1 0 0)) "

cells := (1 to: 500) collect: [:row | (1 to: 500) collect: [:cell | #(0 1) atRandom]].
[500 timesRepeat: [cells := life value: cells]] timeToRun "=> 267282(msec) "
0532デフォルトの名無しさん2012/04/25(水) 20:45:17.23
>>531をRubyに翻訳してみた版。1.9だが50世代に4分以上かかってしまう。
翻訳の手間を省くのにArray#*,#+を置き換えちゃったのが足を引っ張ったか?

require "benchmark"

class Array
  def *(x); zip(x.kind_of?(Array)?x:Array.new(size,x)).map{|e|e.reduce(&:*)} end
  def +(x); zip(x.kind_of?(Array)?x:Array.new(size,x)).map{|e|e.reduce(&:+)} end
end

def life(ary2d)
  sum = ary2d * 0
  (-1..1).each{ |dx| (-1..1).each{ |dy|
    sum += ary2d.map{ |row| row.rotate(dx) }.rotate(dy) } }
  survivs = [3,4].map{ |alive| sum.map{ |row| row.map{ |cell| (cell == alive)?1:0 } } }
  survivs.first + (survivs.last * ary2d)
end

p life([
  [0,1,1,1,0],
  [0,1,0,0,0],
  [0,0,1,0,0],
  [0,0,0,0,0],
  [0,0,0,0,0]])

#=> [[0,1,1,0,0],[0,1,0,1,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0]]

cells = (1..500).map{ (1..500).map{ [0,1].sample } }
p Benchmark.measure{ 50.times{ cells = life(cells) } }
0533デフォルトの名無しさん2012/04/25(水) 22:15:29.46
1.6GHz Core i5で2分


import qualified Data.Vector.Unboxed as V
import qualified Data.List as L
import System.Random.Mersenne

data Lattice = Lattice! Int Int (V.Vector Int)

(!) (Lattice m n v) (i,j) = v V.! (n * mod i m + mod j n)

next b i j = case (sum xs, b ! (i,j)) of
                  (3, _) -> 1
                  (4, 1) -> 1
                  (_, _) -> 0
  where xs = [b ! ((i+m),(j+n)) | m <- [-1,0,1], n <- [-1,0,1]]

updateBoard board@(Lattice m n v) =
  Lattice m n $! V.fromList [next board i j | i <- [0..m-1], j <- [0..n-1]]

randomBoard rs x y = Lattice x y $ V.fromList $ take (x * y) rs

main = do
  rs <- newMTGen Nothing >>= randoms
  let board = randomBoard (map (`mod` 2) rs) 500 500
  print $ L.foldl' (\x _ -> updateBoard x) board [1..500]
05345332012/04/25(水) 22:20:37.27
instance Show Lattice where
  show (Lattice m n v) = concat $ snd $ L.mapAccumL (\i x ->
    if i == n-1 then (0, show x ++ "\n") else (i+1, show x)) 0 $ V.toList v

lattice xss = Lattice n m $ V.fromList $ concat xss
  where
    n = length xss
    m = length (concat xss) `div` n


> updateBoard $ lattice
              [[0,1,1,1,0],
               [0,1,0,0,0],
               [0,0,1,0,0],
               [0,0,0,0,0],
               [0,0,0,0,0]]

# 出力
01100
01010
00000
00000
00100
0535デフォルトの名無しさん2012/04/26(木) 20:54:15.37
(_, _)   (`mod` 2)   (\x _ ->
0536デフォルトの名無しさん2012/04/26(木) 20:56:38.97
最近Lispさんを見かけないけどもう廃れちゃったの?
0537デフォルトの名無しさん2012/04/26(木) 21:25:38.01
言語仕様を共通にするというトレンドは終わった
個別の実装は始まってなかった
0538デフォルトの名無しさん2012/04/27(金) 01:17:14.79
Rで
life <- function(ary2d) {
  sum <- rbind(ary2d[ncol(ary2d),], ary2d[-ncol(ary2d),]) + ary2d + rbind(ary2d[-1,], ary2d[1,])
  sum <- cbind(sum[,nrow(sum)], sum[,-nrow(sum)]) + sum + cbind(sum[,-1], sum[,1])

  ifelse(sum == 3 | (ary2d == 1 & sum == 4), 1, 0)
}
0539デフォルトの名無しさん2012/04/27(金) 08:45:31.15
>>536
2chで世間が判った気になり始めたら色々ヤバイな。
0540デフォルトの名無しさん2012/04/27(金) 10:14:19.97
>>538
500x500 500世代で測ったら 1.8GHz Core i7 で 68秒だった。けっこう速いね。
0541デフォルトの名無しさん2012/04/27(金) 11:00:18.10
ライフゲームで関数型とオブジェクト指向の何を比較したいんだろう?

>>525は次世代を返す関数としてるけどオブジェクト指向側は
 lg = new lifegame(500,500);
 for(i=0;i<500;i++)lg.life();
 console(lg);
って感じでいいの?
そうしないと関数型 vs 手続き型みたいなことになるよね
0542デフォルトの名無しさん2012/04/27(金) 11:37:20.76
例えばF#とC#を比較したら関数型言語と手続き型言語の比較になる
本物のOOは言語に依存しない
関数型言語と対立するようなOOは偽物
0543デフォルトの名無しさん2012/04/27(金) 12:00:12.21
>>541
ライフゲームは単純だけどパラダイムの特徴をかろうじて出せるくらいの規模はあるんじゃない?
お題にあるlifeという関数名(メソッド名)にこだわらなくていいと思うよ。
要は小さな例での正常動作と、500x500セル 500世代(必要なら50世代とかに軽減して)
にどのくらいかかるかが示せていればOKかと。
0544デフォルトの名無しさん2012/04/27(金) 12:17:25.49
>>543
規模の大きさは良いと思うけど、
データの破壊的操作ができると有利な御題のほうが
違いが出て良いと思った

Haskellで配列使ったバージョン


import Data.Array

life ary = array ((1,1),(x,y)) [((i,j), f i j) | i <- [1..x], j <- [1..y]]
  where
    (x,y) = snd $ bounds ary
    f i j = let n = sum [ary ! (g x (i+a), g y (j+b)) | a <- [-1,0,1], b <- [-1,0,1]]
            in if n == 3 || (n == 4 && ary ! (i,j) == 1) then 1 else 0
    g x i = if i < 1 then x else if i > x then 1 else i
0545デフォルトの名無しさん2012/04/27(金) 14:36:04.79
javascriptで書いてみた。破壊的操作有りで。
ソースの長さ汚さは勘弁してください。
http://ideone.com/xNY9J
※↑は5秒制限のため500回でなく1回だけ

lg.life(500);
console.log("life500:" + (new Date()-st) + " msec");
に書き換えてから
windows版node.js(pen4 2.6GHz)でやったら30秒くらいだった。

>node.exe life.js
0,1,1,1,0
0,1,0,0,0
0,0,1,0,0
0,0,0,0,0
0,0,0,0,0
---------------
0,1,1,0,0
0,1,0,1,0
0,0,0,0,0
0,0,0,0,0
0,0,1,0,0
---------------
create :39 msec
life500:29794 msec
0546デフォルトの名無しさん2012/04/27(金) 20:27:45.31
てきとーにCで書いてみた
500回はさすがに秒数制限に引っかかったけど、50回で0.69秒

http://ideone.com/a7mH5
0547デフォルトの名無しさん2012/04/27(金) 22:35:14.09
F# 2.6GHz Core2Duo 500世代で2分57秒

let life (field : int[,]) =
    let height, width = field.GetLength 0, field.GetLength 1
    field |> Array2D.mapi (fun y x c ->
        let s =
            seq { y - 1 .. y + 1 } |> Seq.sumBy (fun y' ->
                seq { x - 1 .. x + 1 } |> Seq.sumBy (fun x' ->
                    field.[(y' + height) % height , (x' + width) % width]))
        match s, field.[y, x] with 4, 1 | 3, _ -> 1 | _ -> 0)
0548デフォルトの名無しさん2012/04/27(金) 22:37:08.83
手続き型言語F#で書くと>>547と同じ環境で500世代9秒

let life (field : int[,]) =
    let height, width = field.GetLength 0, field.GetLength 1
    let result = Array2D.zeroCreate height width
    for y = 0 to height - 1 do
        for x = 0 to width - 1 do
            let mutable s = 0
            for y' = y - 1 to y + 1 do
                for x' = x - 1 to x + 1 do
                    s <- s + field.[(y' + height) % height, (x' + width) % width]
            result.[y, x] <- match s, field.[y, x] with 4, 1 | 3, _ -> 1 | _ -> 0
    result
0549デフォルトの名無しさん2012/04/28(土) 00:03:43.28
OOPならセルごとにオブジェクトで、と思ったが、
仕様が全状態の配列から配列への変換なのね。
0550デフォルトの名無しさん2012/04/28(土) 00:54:50.29
>>549
べつにこだわらなくてもいいでしょ。組みやすいように組めば。
要は小さな例での動作確認出力結果と、
500x500セル 500世代(必要なら50世代とかに軽減して)の計測結果を示せればOK。
0551デフォルトの名無しさん2012/04/28(土) 04:39:34.80
まあ出題者が関数的なアタマなんだろう
0552デフォルトの名無しさん2012/04/28(土) 06:37:42.91
セルごとにオブジェクトとかねぇよww
0553デフォルトの名無しさん2012/04/28(土) 07:45:09.18
問題領域がどこかわかれば何処をオブジェクトにしたら良いか分かるよ
0554デフォルトの名無しさん2012/04/28(土) 09:32:38.01
なかなか面白いじゃないか。
オブジェクト指向で設計されたライフゲーム、頼む。
0555デフォルトの名無しさん2012/04/28(土) 09:44:59.90
この題じゃ>>541くらいにしかならんだろ
オブジェクト指向をどういうもんだと思ってんだよw
0556デフォルトの名無しさん2012/04/28(土) 10:37:13.10
セル毎にオブジェクトか、面白そうだしちょっとやってみるかな
0557デフォルトの名無しさん2012/04/28(土) 10:51:25.73
セル毎にオブジェクトってこんなの?(コードはPython)


class Cell(object):
    def __init__(self, alive):
        self.neighborhood = []
        self.alive = alive
    def evaluate(self):
        s = sum(x.alive for x in self.neighborhood)
        self._alive = 1 if s == 3 or (s == 4 and self.alive == 1) else 0
    def update(self):
        self.alive = self._alive


全部は長いのでこっち
http://ideone.com/3WKkG
0558デフォルトの名無しさん2012/04/28(土) 11:05:27.26
8coreのXeonマシンでOpenMP使ってCのコードを並列化したら
500*500の500世代で1秒切ったわw
0559デフォルトの名無しさん2012/04/28(土) 12:11:25.24
>>557
他スレで遊んでる内に作られてしまった…
0560デフォルトの名無しさん2012/04/28(土) 12:13:20.34
>>552
ライフゲームは生物が単純だから変に思えるかもしれないけど、
これがゲームのキャラクターと考えればごく普通の考え方。

ライフゲームはどの生物も同じ能力だけど、セルがオブジェクトなら
実際の生物みたく、オブジェクトごとに能力を変えることだって出来る

というかそういうゲームがあったね。

マルチプレイヤー・ネットワーク・ゲームTerrarium
http://www.atmarkit.co.jp/fdotnet/wwebserv/wwebserv010/wwebserv010-001.html
> プレイヤーは各自プログラミングした動物を持ち寄り、フィールド上で動物同士を戦わせる。
0561デフォルトの名無しさん2012/04/28(土) 12:23:40.64
やっぱりオブジェクト指向だと規模が大きくなる。

逆に言えば、規模が大きい場合は
オブジェクト指向が有利ってことか。
0562デフォルトの名無しさん2012/04/28(土) 12:42:19.17
大規模で全貌の把握がしづらいものを
個々人では把握できないままでも比較的扱いやすいのがOOPLだと思ってる
0563デフォルトの名無しさん2012/04/28(土) 12:57:03.02
全体を統一しづらい規模になると言語は一つではなくなる
Objective-C++/CLIのような状態
0564デフォルトの名無しさん2012/04/28(土) 16:19:14.44
>セルがオブジェクトなら
>実際の生物みたく、オブジェクトごとに能力を変えることだって出来る

大抵のOOPLにはマルチメソッドすらないのに、
良くそんな大口たたけるな。
0565デフォルトの名無しさん2012/04/28(土) 16:24:25.86
無いのはマルチメソッドを実現するための言語仕様であって、
マルチメソッド自体は実装できるからね。
0566デフォルトの名無しさん2012/04/28(土) 16:25:24.90
>>564
突然何言い出してんのこの子(´・ω・`)
0567デフォルトの名無しさん2012/04/28(土) 16:28:06.39
ホーミングミサイルの話でボコボコにされたやつだ。
気にすんな
0568デフォルトの名無しさん2012/04/28(土) 18:10:20.59
>>565
関数型言語でも実装できる
パラダイムじゃなく言語間の比較スレなんだから
そんなこと言っても意味ない
0569デフォルトの名無しさん2012/04/28(土) 18:15:28.58
>>561
仮に「OOPだと規模が大きくなる」が真だとしても
そこから「規模が大きいとOOPは有利」は導けない
0570デフォルトの名無しさん2012/04/28(土) 18:53:58.34
静的型付けの割に簡潔に書けて、かつ型チェックも厳しくやってほしい

こういうニーズに関数型言語が応えてるから使ってるだけで、
関数型言語使ってる奴が皆OOを嫌ってるわけでも
設計レベルで使わないわけでもないんよ

争いは不毛だ
0571デフォルトの名無しさん2012/04/28(土) 19:06:33.77
> 静的型付けの割に簡潔に書けて、かつ型チェックも厳しくやってほしい
なんとなくC#を思いだしたけどC#で書く人いないね
0572デフォルトの名無しさん2012/04/28(土) 19:31:55.12
争わなかったらスレの存在意義がないだろ
0573デフォルトの名無しさん2012/04/28(土) 20:25:37.43
>>571
C#のジェネリックってダックタイピングできないんでしょ?簡潔かなぁ。
0574デフォルトの名無しさん2012/04/28(土) 20:41:49.41
>>560
ライフゲームのセルっていう文脈だからねぇよって言ったわけで
ゲームのキャラクターのオブジェクト化まで否定はしてねぇよw

>>564
またホーミングの子www
0575デフォルトの名無しさん2012/04/28(土) 21:39:52.98
>>570
Scalaがそう。

静的言語で、簡潔に書けることを
証明した言語。
0576デフォルトの名無しさん2012/04/28(土) 21:45:24.53
>>575
このスレでまだ一回もScala出て来てないぞ
ライフゲームで良いからコードで証明してみてくれ
0577デフォルトの名無しさん2012/04/28(土) 23:03:24.87
「Scalaは簡潔に書けると証明した」=>「じゃあチョット書いてみて」=> 逃亡


どんなコントだよwww
0578デフォルトの名無しさん2012/04/28(土) 23:11:10.96
ん? Scala知らないの?
0579デフォルトの名無しさん2012/04/28(土) 23:31:57.42
Scala待ちの間にw、Squeak Smalltalkでセルがオブジェクト版。(要クラスブラウザ)
細かい違いを無視すれば Python の >>557 とほぼ同じ方針。

Object subclass: #Cell
   instanceVariableNames: 'neighbors next'
Cell >> setBit: int
   neighbors := OrderedCollection with: int
Cell >> collectNeighborsAt: pos in: array2D
   neighbors addAll: (#(-1 0 1) gather: [:dx | #(-1 0 1) collect: [:dy |
      (array2D atWrap: (pos y + dy)) atWrap: (pos x + dx)]]); remove: self
Cell >> calcNext
   next := (neighbors inject: 0 into: [:sum :neigh | sum + neigh value])
      caseOf: {[3]->[1]. [4]->[self value]} otherwise: [0]
Cell >> update
   neighbors at: 1 put: next
Cell >> value
   ^neighbors first
Cell >> printOn: stream
   self value printOn: stream
Cell class >> newWith: bitInt
   ^self new setBit: bitInt; yourself
Cell class >> newLatticeFrom: array2D
   | lattice |
   lattice := array2D collect: [:row | row collect: [:bit | Cell newWith: bit]].
   ^lattice doWithIndex: [:row :y | row doWithIndex: [:cell :x |
      cell collectNeighborsAt: x@y in: lattice]]; yourself
Cell class >> updateLattice: array2D
   ^array2D do: [:row | row do: #calcNext]; do: [:row | row do: #update]

| lattice |
lattice := Cell newLatticeFrom: {{0. 1. 1. 1. 0}. {0. 1. 0. 0. 0}. {0. 0. 1. 0. 0}. {0. 0. 0. 0. 0}. {0. 0. 0. 0. 0}}.
Cell updateLattice: lattice. "=> {{0. 1. 1. 0. 0}. {0. 1. 0. 1. 0}. {0. 0. 0. 0. 0}. {0. 0. 0. 0. 0}. {0. 0. 1. 0. 0}} "
0580デフォルトの名無しさん2012/04/29(日) 00:22:22.02
純粋な関数型言語って、参照するたびに値が変化する変数みたいなのは作れるの?
たとえば乱数とか、参照した時点の現在時刻を値として持ってる変数とか
0581デフォルトの名無しさん2012/04/29(日) 00:31:18.37
>557をscalaでベタ移植してみた。

case class Cell(var alive:Int) {
 var neighborhood = List[Cell]()
 var alive_ = 0
 def evaluate() {
  val s = neighborhood.map(_.alive).sum
  alive_ = if(s == 3 || s == 4 && alive == 1) 1 else 0
 }
 def update() { alive = alive_ }
}
case class Board(val lattice:List[List[Int]]) {
 val cells = lattice.map(_.map(x => Cell(x)))
 val m = lattice.size; val n = lattice(0).size
 for(i <- 0 until m; j <- 0 until n; k <- -1 to 1; l <- -1 to 1)
  cells(i)(j).neighborhood ::= cells((i+k+m)%m)((j+l+n)%n)
 def life() {
  cells.foreach(_.foreach(_.evaluate))
  cells.foreach(_.foreach(_.update))
 }
 override def toString() = {
  cells.map(_.map(_.alive.toString).reduce(_ + "," + _)).reduce(_ + "\n" + _)
 }
}
val board = Board(List(List(0,1,1,1,0),List(0,1,0,0,0),List(0,0,1,0,0),List(0,0,0,0,0),List(0,0,0,0,0)))
board.life
print(board)

scalaの機能を余り活用できていない感じ。
0582デフォルトの名無しさん2012/04/29(日) 01:14:20.15
これで静的型付け言語なんだぜ。

val msg = if (true) "true dayo" else "false dayo"
0583デフォルトの名無しさん2012/04/29(日) 01:27:13.41
せっかくなのですべてのセルが並行に動くように>581を修正

case class Cell(var alive:Int) extends Actor {
 var neighborhood = List[Cell]()
 def act() = {
  neighborhood.foreach(_ ! alive)
  var count = 0; var s = 0
  loopWhile(count < neighborhood.size) {
   receive { case i:Int => s += i; count += 1 }
  } andThen { alive = if(s == 3 || s == 4 && alive == 1) 1 else 0 }
 }
}
case class Board(val lattice:List[List[Int]]) {
 val cells = lattice.map(_.map(x => Cell(x)))
 val m = lattice.size; val n = lattice(0).size
 for(i <- 0 until m; j <- 0 until n; k <- -1 to 1; l <- -1 to 1)
  cells(i)(j).neighborhood ::= cells((i+k+m)%m)((j+l+n)%n)
 def life() {
  cells.foreach(_.foreach(_.start))
 }
 override def toString() = cells.map(_.map(_.alive.toString).reduce(_ + "," + _)).reduce(_ + "\n" + _)
}
val board = Board(List(List(0,1,1,1,0),List(0,1,0,0,0),List(0,0,1,0,0),List(0,0,0,0,0),List(0,0,0,0,0)))
board.life
print(board)

evaluate/updateの分割が不要になったので少し短くなったか
0584デフォルトの名無しさん2012/04/29(日) 01:30:58.02
これで静的型付け言語なのか。
本当に短いコードは動的型付け言語だけの特権じゃないことを
証明してしまったな。
0585デフォルトの名無しさん2012/04/29(日) 02:11:32.74
ただ静的型にしては遅いよね。
500x500 500世代で動的な >>579 が 112秒なのに、>>581 は 196秒。
0586デフォルトの名無しさん2012/04/29(日) 02:18:22.73
>>585
それ事前コンパイルしてないだろ?
0587デフォルトの名無しさん2012/04/29(日) 02:35:44.97
>>583
これって一回のlifeのコール後、
すべてのセルがアップデートを終えるのをどこで待ち合わせているの?
0588デフォルトの名無しさん2012/04/29(日) 06:27:13.54
>>582
そんなんで感動できるとか何時の時代の人?

OCaml : let msg = if true then "true" else "false"
Haskell : let msg = if True then "true" else "false"
0589デフォルトの名無しさん2012/04/29(日) 06:30:26.82
どうせ、RubyとかLLばっかり使ってる人だろw
0590デフォルトの名無しさん2012/04/29(日) 07:52:20.17
C++,C#にも導入されたね
C++11 : auto msg = true ? "true dayo" : "false dayo";
C#(3.0) : var msg = true ? "true dayo" : "false dayo";
0591デフォルトの名無しさん2012/04/29(日) 08:14:29.69
最近どんどん動的型付け言語の
メリットがなくなっていくね。
0592デフォルトの名無しさん2012/04/29(日) 08:47:25.44
>>590
…それでmsgの型を推論しろってか。
0593デフォルトの名無しさん2012/04/29(日) 09:24:13.53
>>591
この戦いが終わったら全ての武器のメリットがなくなるんだ
0594デフォルトの名無しさん2012/04/29(日) 09:42:55.39
機械語のメリットがなくなってゆくね、とか言ってる奴の同類だよなぁw
0595デフォルトの名無しさん2012/04/29(日) 09:43:05.44
でも静的型はコンパイルが必要でREPLももっさり、型推論も万能じゃない
スクリプト言語はこれからも残るよ
0596デフォルトの名無しさん2012/04/29(日) 10:59:45.94
trueって名前の変数を作って、遅延評価によってmsgを参照したときの変数trueの値によりmsgの値も変わるってことでいいんかの
変数trueに再代入できたりしないとあんま意味なくね?
いや違ってたらすまんが
0597デフォルトの名無しさん2012/04/29(日) 11:11:11.60
>>590は型推論の話じゃないの?
"true dayo"も"false dayo"も文字列リテラルなので
三項演算の条件のtrue/falseを問うことなくmsgの型を文字列と確定できる
0598デフォルトの名無しさん2012/04/29(日) 11:27:23.87
>>597
ああなんだそういうことか、勘違いしてたわ
0599デフォルトの名無しさん2012/04/29(日) 11:55:08.69
変数に互換性がない別の型の値を
再代入できる言語はクソです。
0600デフォルトの名無しさん2012/04/29(日) 12:10:48.87
>>586
Scalaって事前(?)にコンパイルする以外になんか実行方法あったっけ?
0601デフォルトの名無しさん2012/04/29(日) 12:18:53.17
>>600

>>581はコンパイルしたらエラーがでます。
0602デフォルトの名無しさん2012/04/29(日) 12:21:46.03
コンパイルしない場合は、そのまま動きます。
0603デフォルトの名無しさん2012/04/29(日) 12:31:37.65
>581はscalaスクリプトだから、コンパイルする場合は
-Xscript XXX オプションをつける必要があるかと
0604デフォルトの名無しさん2012/04/29(日) 12:42:00.90
動くね

$ time scala Lifegame.scala
0,1,1,0,0
0,1,0,1,0
0,0,0,0,0
0,0,0,0,0
0,0,1,0,0
scala Lifegame.scala 1.44s user 0.09s system 4% cpu 37.965 total
AMD MV-40 1.6GHz シングルコア
0605デフォルトの名無しさん2012/04/29(日) 12:42:30.36
>>599
それで、代入を禁止するのと共用体を禁止するのは、どっちが良いんですか
0606デフォルトの名無しさん2012/04/29(日) 12:48:02.58
スクリプト実行
time scala LifeGame.scala
0,1,1,0,0
0,1,0,1,0
0,0,0,0,0
0,0,0,0,0
0,0,1,0,0
real 0m1.819s
user 0m0.704s
sys 0m0.104s

コンパイル実行
time scala LifeGame
0,1,1,0,0
0,1,0,1,0
0,0,0,0,0
0,0,0,0,0
0,0,1,0,0
real 0m0.585s
user 0m0.528s
sys 0m0.072s

コンパイル時間の分、スクリプト実行だと起動に時間がかかるね
■ このスレッドは過去ログ倉庫に格納されています