鍋あり谷あり

テーマを決めずに適当に書いています。

引き続き Haskell

引き続き Haskell
今回の課題は、list の中から n 個選ぶ選び方を全て列挙する、という問題。
たとえば関数名を allCombi とすると、allCombi 2 [1,2,3,4,5] は、[ [1,2], [1,3], [1,4], [1,5], [2,3], [2,4], [2,5], [3,4], [3,5], [4,5] ] を返せばよい。
ちなみにたぶん、stdio/stdlib のみを前提に C 言語で書くと結構大変なことになる。
ruby でも、直感の赴くままにするするっと書けたりはしなかった。
で。Haskell だと:

import System
import Numeric

dropOne n x = take n x ++ drop (n+1) x
flattenOne [] = []
flattenOne (x:xs) = x ++ flattenOne xs

allCombi n list = f n list 0
  where 
    f n list iMin | n==0 = [[]]
                  | True = flattenOne $ map subsAndCur ix
                  where 
                    ix = [iMin..( length list - 1) ]
                    sub i = f (n-1) (dropOne i list) i
                    subsAndCur i = map ([ list !! i ]++) (sub i)

testfunc x = allCombi (x!!0) [1..x!!1]

main = test testfunc
 where 
    test f = getArgs >>= putStr . show . f . argToNum
    argToNum = map $ fst . head . readDec

こんな感じ。
これも、ruby で書いたのと大差なかった。
ソースの複雑さも、実行速度も大差ない。
課題の選び方がまずいのか。それとも私の書き方がまずいのか。
しかし。これももっともっと簡単に書けそうな気がする。モナドがあればいいのかな。