定食屋おろポン

おろしポン酢と青ネギはかけ放題です

アリンコの問題といた

職業プログラマがFizzBuzz書けない理由
タイトル: Ants
問題文: 長さL cmの竿の上をn匹のアリが毎秒1cmのスピードで歩いています。アリが竿の端に到達すると竿の下に落ちていきます。また、竿の上は狭くてすれ違えないので、二匹のアリが出会うと、それぞれ反対を向いて戻っていきます。各アリについて、現在の竿の左端からの距離xiはわかりますが、どちらの方向を向いているのかはわかりません。すべてのアリが竿から落ちるまでにかかる最小の時間と最大の時間をそれぞれ求めなさい。
制約: 1≦L≦106 1≦n≦106 0≦xi≦L
出典: プログラミングコンテストチャレンジブック(p.23) / 元はPOJ No.1852

むずかしいことはわからないけど、とりあえずHaskellでかいてみたよ。

distanceFromEdge :: Float -> Float -> Float
distanceFromEdge l x
	| l < 0.0 || x < 0.0 || x > l	= error "cant calc"
	| otherwise 			= if x < l * 0.5 then x	else l - x

ant :: Float -> [Float] -> (Float, Float)
ant l []		= (l, 0)
ant l (x:xs)	= (minFromEdge, l - minFromEdge)
	where
		minFromEdge = min (distanceFromEdge l x) (fst (ant l xs))

ant' :: Float -> [Float] -> (Float, Float)
ant' l xs = (minFromEdge, l - minFromEdge)
	where
		minFromEdge = minimum (map (distanceFromEdge l) xs)

main = do
	putStrLn (show(ant 10.0 [5.0, 2.0, 8.0, 4.0, 1.5, 3.0]))
=> (1.5, 8.5)

引数が小文字Lだと|(vertical bar)と区別つかないですね。
まだHaskellのコードを読んだことがないので、"Haskellらしさ"がわからない。
なるべくその言語らしい書き方を心掛けたいけど、わからないからフワフワしてる。

distanceFromEdge

distanceFromEdge :: Float -> Float -> Float
distanceFromEdge l x
	| l < 0.0 || x < 0.0 || l < x	= error "cant calc"
	| otherwise 			= if x < l * 0.5 then x	else l - x

インデントの作法がわからん。
ガード使う時って、"="の位置合わせたりするのかな。
if, elseは一行で書かないほうがいいのかな。

ant

ant :: Float -> [Float] -> (Float, Float)
ant l []		= (l, 0)
ant l (x:xs)	= (minFromEdge, l - minFromEdge)
	where
		minFromEdge = min (distanceFromEdge l x) (fst (ant l xs))

とりあえず再帰でも使っとけばええんやろ?ちゃうの?的な安易な発想。
whereのインデントはいくつ置けばいいの。。

ant'

ant' :: Float -> [Float] -> (Float, Float)
ant' l xs = (minFromEdge, l - minFromEdge)
	where
		minFromEdge = minimum (map (distanceFromEdge l) xs)

部分適用とか使ったら関数型っぽいんやろ?ちゃうの?的な安易な発想。

感想

インデントと改行の作法を求めて旅に出ます。