プログラマとプロマネのあいだ

プログラマもやるし、プロマネもやるし、たまに似非アーキとか営業っぽいこともやるITエンジニアがスキルアップの話を中心に日常を綴るブログです。

関数型宣言の追記&nlistToStringの一般化 (0〜9の数字を使って、掛け算して、Go!解けた。)

前出の

nlistToString nl = concatMap show nl

ですが、数値のリストを文字列にするために用意した関数でしたが、別に数値のリストじゃなくてもよいのでは?と思い、以下のようにしてみることに。

listToString :: [a] -> String
listToString l = concatMap show l

が、大量(?)のコンパイルエラーが発生。

kake.hs:16:27:
    Could not deduce (Show a) from the context ()
      arising from a use of `show' at kake.hs:16:27-30
    Possible fix:
      add (Show a) to the context of
        the type signature for `listToString'
    In the first argument of `concatMap', namely `show'
    In the expression: concatMap show l
    In the definition of `listToString':
        listToString l = concatMap show l

なんのこっちゃと思ったらどうも、Java的に言えば、

String listToString(Object o)
{
    concatMap(show(o));
}
String show(Showable s)
{
    return s.toString();
}

という感じで、show関数はShowableな型を期待しているのに、listToString関数はshow関数に対してObject型(Haskell的には多相型)を渡してしまっているということのようです。


こんな風にするとうまくいきます。

listToString :: (Show a) => [a] -> String
listToString l = concatMap show l

[a]はShow可能である(Showable)という制限を付けたってことですね。


最終的なソースはこうなりました。

import List

main = putStr $ unlines $ map format $ filter test $ perm [0,1,2,3,5,6,7,8,9]

perm :: [Int] -> [[Int]]
perm [] = [[]]
perm xs = concat [map (x:) $ perm (delete x xs) | x <- xs]

test :: [Int] -> Bool
test [a,b,c,d,e,f,g,h,i] = if (400 + a*10 + b) * (c*10 + d) == (e*10000 + f*1000
 + g*100 + h*10 + i) then True else False

format :: [Int] -> String
format [a,b,c,d,e,f,g,h,i] = listToString [4,a,b] ++ " x " ++ listToString[c,d]
++ " = " ++ listToString [e,f,g,h,i]

listToString :: (Show a) => [a] -> String
listToString l = concatMap show l

permも多相型化できそう。