みくにまるのブログ

意識低い系ブロガー、みくにまるが送るブログ。

HaskellでAOJ ITP1_2_A大小関係

Haskellの練習がてらAOJをちまちま解いてみる。
とりあえずトップページから
誰かが解いてる問題に適当に飛んで行けそうなら解くという方針。

早速最初の問題は
大小 等価 | プログラミング入門 | Aizu Online Judge

2つの整数 a, b を読み込んで、a と b の大小関係を出力するプログラムを作成して下さい。

ふむふむ
これくらいならググりながら解けばなんとかなりそうだ。

いきなり詰む

main = do
  s <- getLine
  let [a,b] = map read $ words s
  if (a > b)
     then do
       print "a > b"
       else
         if (a < b)
            then do
              print "a < b"
            else
              print "a == b"

こんな感じで書いてみたのだが
コンパイルエラー

Ambiguous type variable ‘a0’ arising from a use of ‘read’ prevents the constraint ‘(Read a0)’ from being solved.
Relevant bindings include
a :: a0 (bound at ITP1_2_A.hs:3:8)
b :: a0 (bound at ITP1_2_A.hs:3:10)
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Read Ordering -- Defined in ‘GHC.Read’
instance Read Integer -- Defined in ‘GHC.Read’
instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
...plus 22 others
...plus four instances involving out-of-scope types
(use -fprint-potential-instances to see them all)

早くもギブアップ

型に関するエラーらしいのだが
訳がわからないのでチラッと回答例を参考にする事にした。
yoshさんの回答を参考に自分のコードに取り入れる。

解決策が判明

どうやら

  let [a,b] = map read $ words s

という部分を

  let [a,b] :: [Int] = map read $ words s

といった具合に書き換えて型を明示すれば良いらしい。
しかし単に::[Int]を加えただけだと

Illegal type signature: ‘[Int]’ Type signatures are only allowed in patterns with ScopedTypeVariables

というエラーが出てしまうので
ファイルの先頭に

{-# LANGUAGE ScopedTypeVariables #-}

ScopedTypeVariablesという言語拡張を加えてエラーを回避する。
参考 Scoped type variablesが必要になるとき - maoeのブログ

これghcじゃなかったらどう解決するのだろうか。
深く考えるのは後にしてとりあえずコードを手直し

{-# LANGUAGE ScopedTypeVariables #-}
main :: IO ()
main = do
  s <- getLine
  let [a,b]::[Int] = map read $ words s
  if a > b
     then
       print "a > b"
       else
         if a < b
            then
              print "a < b"
            else
              print "a == b"

IDEに注意された箇所も修正して
出来上がった上記のコードを判定に突っ込む。 f:id:mikunimaru:20171111035927p:plain
駄目じゃん!!

間違いの原因を探る

手元でrunghcをして動かしてみると

10 1
"a > b"

このような出力になっていた。
おそらく"が邪魔なのだろう。
printをputStrLnに変更

{-# LANGUAGE ScopedTypeVariables #-}
main :: IO ()
main = do
  s <- getLine
  let [a,b]::[Int] = map read $ words s
  if a > b
     then
       putStrLn "a > b"
       else
         if a < b
            then
              putStrLn "a < b"
            else
              putStrLn "a == b"

今度は通った。
全然スマートではないけど。