【激突】関数型言語 VS オブジェクト指向言語2
■ このスレッドは過去ログ倉庫に格納されています
0001営利利用に関するLR審議中@詳細は自治スレへ
2012/04/07(土) 21:26:47.61一部には関数型言語を崇拝している人もいます
どちらが上なのか、この際はっきりさせましょう
前スレ http://toro.2ch.net/test/read.cgi/tech/1331328955/
0495デフォルトの名無しさん
2012/04/18(水) 13:10:30.340496デフォルトの名無しさん
2012/04/18(水) 13:31:40.560497デフォルトの名無しさん
2012/04/19(木) 02:49:08.33sub { my $x = shift;
$f->($f->($x)) } };
$rst = $t->($t)->($t)->($t)->(
sub{ my $x = shift;
$x + 1 })->(0);
print $rst, "\n";
0498デフォルトの名無しさん
2012/04/19(木) 09:02:56.87ケチがついた、オープンクラス、メソッドチェーン、リフレクションは無しで
require 'test/unit'
def fb(x, cnd, msg)
th = Thread.current
x.kind_of?(Integer) ? (th[:m] = n = x; s = "") : (n = th[:m]; s = x)
cnd[n] ? s + msg : !s.empty? ? s : n
end
def fizz(n); fb(n, proc{ |n| n%3==0 }, "Fizz") end
def buzz(n); fb(n, proc{ |n| n%5==0 }, "Buzz") end
def gizz(n); fb(n, proc{ |n| n%7==0}, "Gizz") end
class FizzBuzzQuizTest < Test::Unit::TestCase
def test_fbq
assert_equal( fizz(1), 1 )
assert_equal( fizz(3), "Fizz" )
assert_equal( buzz(fizz(1)), 1 )
assert_equal( buzz(fizz(3)), "Fizz" )
assert_equal( buzz(fizz(5)), "Buzz" )
assert_equal( buzz(fizz(15)), "FizzBuzz" )
assert_equal( gizz(buzz(fizz(105))), "FizzBuzzGizz" )
assert_equal( buzz(gizz(fizz(105))), "FizzGizzBuzz" )
end
end
0499デフォルトの名無しさん
2012/04/19(木) 09:53:30.31クソみたいな実装が出てくる出題だったけど
言語比較に役立つ何かは得られましたか?
0500デフォルトの名無しさん
2012/04/19(木) 10:07:54.14動的型であれ作るもんじゃないという幼稚園児並みの洞察が得られました
0501デフォルトの名無しさん
2012/04/19(木) 10:43:06.55「数値と文字列の組」と「数値または文字列」の違いが不明瞭だった。
リフレクションや継承で二つのクラスを一組にしたいのか、
それとも一つのクラスを数種類に分けたいのか明示されていなかった。
0502デフォルトの名無しさん
2012/04/19(木) 10:53:45.22関数的にはどう記述したらいいのかよかったら教えてください。
0503デフォルトの名無しさん
2012/04/19(木) 11:37:33.00関数型的にもオブジェクト指向的にも、どう記述したらいいかとか答えようがない。
0504デフォルトの名無しさん
2012/04/19(木) 12:23:49.22どうすればいいのでしょうか。たとえば、状態をfizzとかbuzzから
(引数として渡すことなしに)参照したり更新したりしたいのです。
0505デフォルトの名無しさん
2012/04/19(木) 12:50:34.08いまんとこHaskellからTLSを使う、「これ」といった定番はないようだ
0506デフォルトの名無しさん
2012/04/19(木) 12:58:07.140507デフォルトの名無しさん
2012/04/19(木) 13:20:53.20それは基本的にStateモナドの領域。
Readerモナドの中で、さらにサブルーチン的に他のReaderモナドを呼び出す時に、
一時的に書き換えたように見せかけたい、っていう場合ならばlocal関数が使えるけど。
Readerモナドで更新したいって、読み取り専用変数に書き込みたいって言ってるのと同じ事なのはわかってるよな…?
0508デフォルトの名無しさん
2012/04/19(木) 17:54:57.76(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あるときは a
またあるときは m a
m a -> (a -> m b) -> m b
0510デフォルトの名無しさん
2012/04/20(金) 17:52:20.760511デフォルトの名無しさん
2012/04/20(金) 22:29:27.340512デフォルトの名無しさん
2012/04/20(金) 22:55:07.28・1〜9のカードを各4枚ずつ用意、それをシャッフルして「ストック」とする
・ストックから7枚のカードを引く
・引いたカードの中から、プレイヤーは合計が15になるように数枚を選んで捨てる
(選ばせ方はプログラマが考える、ギブアップ手段も用意)
・捨てなかったカードと合わせて再び7枚になるか、もしくはストックが空になるまでストックからカードを引く
・また15になるように捨てる
・引いては捨ててを繰り返し、ストックと手札が共に空になったらおめでとう的な言葉を吐いて終了
0513デフォルトの名無しさん
2012/04/20(金) 23:16:37.510514デフォルトの名無しさん
2012/04/21(土) 01:27:35.30Squeak 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なぜこの人は今どきSmalltalkの末裔を使っているのか理由をうかがいたいので
おしえてくださいです
0516デフォルトの名無しさん
2012/04/22(日) 01:52:01.88class 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.32stock = ([*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>>514 のコードをどこに入力して、どう実行したら動くんだ?
0519デフォルトの名無しさん
2012/04/22(日) 17:54:43.651. 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.50let 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ありがと。何か前に入れたバージョンでやってみたら「[ | input |」の行の左に「Period or right bracket expected ->」とか出たけど、実行の仕方自体は判ったから色々試してみる。
0522デフォルトの名無しさん
2012/04/23(月) 00:33:02.590523デフォルトの名無しさん
2012/04/23(月) 07:26:59.300524デフォルトの名無しさん
2012/04/24(火) 12:35:28.990525デフォルトの名無しさん
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.010527デフォルトの名無しさん
2012/04/25(水) 14:03:57.26javaもマルチパラダイム化が進むな
OOPLが関数型言語の特徴の一部を取り込む中
スレタイの通り言語比較した場合
「副作用の有無」が一番重要なんじゃないかと思ったけどどうだろう?
機能を取り込むことはあっても無くすことはしないだろうから
副作用の有無が、開発速度や可読性、保守性にどのように影響してくるか・・・
と考えても良いお題は思いつかないんだけどね
0528デフォルトの名無しさん
2012/04/25(水) 15:26:58.18関数型言語使うようになってから、nullを持たない参照型とか、イミュータブルな値型がいかに重要か思い知った。
しかも、イミュータブルな値型を基本として、nullを持った参照オブジェクト型、nullを持たない参照オブジェクト型って形で扱えないと厳しい。
これは言語仕様として取り込まれていないとどうしようもない。
そういう意味では、C++は結構惜しいところまで行ってたと思う。
0529デフォルトの名無しさん
2012/04/25(水) 16:37:33.03値型でも仮想関数があったら元も子もない。
仮想関数をやめてswitchを使う覚悟がないと厳しい。
関数型言語のパターンマッチはswitchと同じ方式だ。
0530デフォルトの名無しさん
2012/04/25(水) 16:43:26.430531デフォルトの名無しさん
2012/04/25(水) 17:35:29.26Squeak 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翻訳の手間を省くのに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.46import 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]
0534533
2012/04/25(水) 22:20:37.27show (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.370536デフォルトの名無しさん
2012/04/26(木) 20:56:38.970537デフォルトの名無しさん
2012/04/26(木) 21:25:38.01個別の実装は始まってなかった
0538デフォルトの名無しさん
2012/04/27(金) 01:17:14.79life <- 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.152chで世間が判った気になり始めたら色々ヤバイな。
0540デフォルトの名無しさん
2012/04/27(金) 10:14:19.97500x500 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本物のOOは言語に依存しない
関数型言語と対立するようなOOは偽物
0543デフォルトの名無しさん
2012/04/27(金) 12:00:12.21ライフゲームは単純だけどパラダイムの特徴をかろうじて出せるくらいの規模はあるんじゃない?
お題にあるlifeという関数名(メソッド名)にこだわらなくていいと思うよ。
要は小さな例での正常動作と、500x500セル 500世代(必要なら50世代とかに軽減して)
にどのくらいかかるかが示せていればOKかと。
0544デフォルトの名無しさん
2012/04/27(金) 12:17:25.49規模の大きさは良いと思うけど、
データの破壊的操作ができると有利な御題のほうが
違いが出て良いと思った
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ソースの長さ汚さは勘弁してください。
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.31500回はさすがに秒数制限に引っかかったけど、50回で0.69秒
http://ideone.com/a7mH5
0547デフォルトの名無しさん
2012/04/27(金) 22:35:14.09let 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.83let 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仕様が全状態の配列から配列への変換なのね。
0550デフォルトの名無しさん
2012/04/28(土) 00:54:50.29べつにこだわらなくてもいいでしょ。組みやすいように組めば。
要は小さな例での動作確認出力結果と、
500x500セル 500世代(必要なら50世代とかに軽減して)の計測結果を示せればOK。
0551デフォルトの名無しさん
2012/04/28(土) 04:39:34.800552デフォルトの名無しさん
2012/04/28(土) 06:37:42.910553デフォルトの名無しさん
2012/04/28(土) 07:45:09.180554デフォルトの名無しさん
2012/04/28(土) 09:32:38.01オブジェクト指向で設計されたライフゲーム、頼む。
0555デフォルトの名無しさん
2012/04/28(土) 09:44:59.90オブジェクト指向をどういうもんだと思ってんだよw
0556デフォルトの名無しさん
2012/04/28(土) 10:37:13.100557デフォルトの名無しさん
2012/04/28(土) 10:51:25.73class 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.26500*500の500世代で1秒切ったわw
0559デフォルトの名無しさん
2012/04/28(土) 12:11:25.24他スレで遊んでる内に作られてしまった…
0560デフォルトの名無しさん
2012/04/28(土) 12:13:20.34ライフゲームは生物が単純だから変に思えるかもしれないけど、
これがゲームのキャラクターと考えればごく普通の考え方。
ライフゲームはどの生物も同じ能力だけど、セルがオブジェクトなら
実際の生物みたく、オブジェクトごとに能力を変えることだって出来る
というかそういうゲームがあったね。
マルチプレイヤー・ネットワーク・ゲーム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.02Objective-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突然何言い出してんのこの子(´・ω・`)
0567デフォルトの名無しさん
2012/04/28(土) 16:28:06.39気にすんな
0568デフォルトの名無しさん
2012/04/28(土) 18:10:20.59関数型言語でも実装できる
パラダイムじゃなく言語間の比較スレなんだから
そんなこと言っても意味ない
0569デフォルトの名無しさん
2012/04/28(土) 18:15:28.58仮に「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.120573デフォルトの名無しさん
2012/04/28(土) 20:25:37.43C#のジェネリックってダックタイピングできないんでしょ?簡潔かなぁ。
0574デフォルトの名無しさん
2012/04/28(土) 20:41:49.41ライフゲームのセルっていう文脈だからねぇよって言ったわけで
ゲームのキャラクターのオブジェクト化まで否定はしてねぇよw
>>564
またホーミングの子www
0575デフォルトの名無しさん
2012/04/28(土) 21:39:52.98Scalaがそう。
静的言語で、簡潔に書けることを
証明した言語。
0576デフォルトの名無しさん
2012/04/28(土) 21:45:24.53このスレでまだ一回もScala出て来てないぞ
ライフゲームで良いからコードで証明してみてくれ
0577デフォルトの名無しさん
2012/04/28(土) 23:03:24.87どんなコントだよwww
0578デフォルトの名無しさん
2012/04/28(土) 23:11:10.960579デフォルトの名無しさん
2012/04/28(土) 23:31:57.42細かい違いを無視すれば 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.37case 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.15val msg = if (true) "true dayo" else "false dayo"
0583デフォルトの名無しさん
2012/04/29(日) 01:27:13.41case 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.74500x500 500世代で動的な >>579 が 112秒なのに、>>581 は 196秒。
0586デフォルトの名無しさん
2012/04/29(日) 02:18:22.73それ事前コンパイルしてないだろ?
0587デフォルトの名無しさん
2012/04/29(日) 02:35:44.97これって一回のlifeのコール後、
すべてのセルがアップデートを終えるのをどこで待ち合わせているの?
0588デフォルトの名無しさん
2012/04/29(日) 06:27:13.54そんなんで感動できるとか何時の時代の人?
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.820590デフォルトの名無しさん
2012/04/29(日) 07:52:20.17C++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…それでmsgの型を推論しろってか。
0593デフォルトの名無しさん
2012/04/29(日) 09:24:13.53この戦いが終わったら全ての武器のメリットがなくなるんだ
0594デフォルトの名無しさん
2012/04/29(日) 09:42:55.39■ このスレッドは過去ログ倉庫に格納されています