#html{{
table border="0" cellpadding="5"><tr><td valign="top"><a href="https://www.amazon.co.jp/exec/obidos/ASIN/4908686076/vertex9-22/" target="_blank"><img src="
" border="0"></a></td><td> </td><td valign="top"><a href="https://www.amazon.co.jp/exec/obidos/ASIN/4908686076/vertex9-22/" target="_blank">プログラミングHaskell 第2版</a><br>Grahum Hutton<br>ラムダノート<br>2019-08-02<br>¥ 3,456</td></tr></table>
}}
p.67
関数は相互再帰を使っても定義できます。
相互再帰とは、二つ以上の関数がお互いを参照し合うことです。
たとえば、プレリュード関数 evenと oddを考えてみましょう。
p.067.hs
#code(haskell){{
even :: Int -> Bool
even 0 = True
even n = odd (n-1)
odd :: Int -> Bool
odd 0 = False
odd n = even (n-1)
}}
これをWinGHCiにロードするとエラーが発生した。
Failed, no modules loaded. Prelude> p067.hs:6:10: error: Ambiguous occurrence ‘odd’ It could refer to either ‘Prelude.odd’, imported from ‘Prelude’ at p067.hs:1:1 (and originally defined in ‘GHC.Real’) or ‘Main.odd’, defined at p067.hs:9:1 | 6 | even n = odd (n-1) | ^^^ p067.hs:10:9: error: Ambiguous occurrence ‘even’ It could refer to either ‘Prelude.even’, imported from ‘Prelude’ at p067.hs:1:1 (and originally defined in ‘GHC.Real’) or ‘Main.even’, defined at p067.hs:5:1 | 10 | odd n = even (n-1) | ^^^^
<エラー調査>
「Ambiguous occurrence」 → 直訳「あいまいな発生」
Preludeモジュールを明示的にimportしておき、hiding構文を使うとインポートを防止することができます。
たとえば以下のようにmapを定義しようとするとエラーになります。map _ [] = [] map f (x:xs) = f x : map f xsGHCiでの実行結果です。
Compiling Main ( a.hs, interpreted ) a.hs:2:21: Ambiguous occurrence `map' It could refer to either `Main.map', defined at a.hs:1:0 or `GHC.Base.map', imported from Prelude at Implicit import declaration Failed, modules loaded: none.以下のようにPreludeモジュールを明示的にimportし、hiding構文でmapを隠します。
import Prelude hiding (map) map _ [] = [] map f (x:xs) = f x : map f xsすると、以下のようにエラーがなくなります。
import Prelude hiding (even, odd) -- 標準関数の even, odd を隠すおまじない
まさにこの一行を先頭に入れたら、エラーメッセージが出なくなった。
●モジュールの使い方
Haskell の場合、モジュールは import 文を使って読み込みます。import モジュール名必要な関数 (変数) だけインポートすることもできます。
import モジュール名 (名前, ...)モジュール名の後ろのカッコの中にインポートする関数を指定します。逆に、インポートしたくない関数を指定することもできます。
import モジュール名 hiding (名前, ...)hiding を付けると、指定された関数はインポートされません。それ以外の関数はすべてインポートされます。
実験のため、Preludeモジュールの標準関数を隠す必要がある場合、
import Xxx hiding (yyy)
のように、先頭でインポートしない宣言をしておく必要がある。
odd, evenは標準関数なので、名前が重複していた?
とりあえず、エラーメッセージが出なくなったので、以後同様の現象が起きたら、このような方法で対処してみよう。
p.67(続き)
Haskell では文字列が文字のリストであることを思い出しましょう。
たとえば、"abcde"は単に ['a','b','c','d','e']の略記法です。