5

「putStrLn」への呼び出しを追加することで、Haskell 関数が適用されるたびに表示されるようにしようとしています。

isPrime2 1 = False

isPrime2 n = do
    putStrLn n
    null (filter (==0) (map (mod n) (filter isPrime2 [2..(floor (sqrt(fromIntegral (n-1))))])))

(最終的な目標は、あるバージョンの isPrime が別のバージョンよりも効率的である理由を実証することです。)

上記のコードを GHCi にロードすると、次のエラーが発生します。

Bool予想されるタイプと実際のタイプを一致させることができませんでしたm0 b0

これはn00bの間違いだと確信しています。誰かが私がやろうとしていることを達成する正しい方法を教えてもらえますか?

4

2 に答える 2

18

問題は、Haskell が やなどの純粋な関数とやなどの非純粋アクションを厳密に区別していることです。純粋な関数は、同じ入力が与えられ、何も変更されていない場合、常に同じ結果が得られるはずです。これは明らかに と の使用を禁止しています。型システムは実際にこの分離を強制します。IO を実行する、または何らかの形で不純である各関数には、その型の前に固執があります。(+)mapputStrLnmainPutStrIO


tl;dr; traceモジュールから使用Debug.Trace

import Debug.Trace

isPrime2 1 = False
isPrime2 n = show n `trace` null (filter (==0) (map (mod n) (filter isPrime2 [2..(floor (sqrt(fromIntegral (n-1))))])))

ただし、コードが実際に実行されるという保証はないため、結果がかなり驚くべきものになる可能性があることに注意してください。trace の引数は、1 回または 2 回、またはその他の回数実行できます。

于 2011-10-04T15:25:01.140 に答える
4

このような型エラーが発生Couldn't match expected type X with actual type Yした場合は、haskell 型システムを使用してガイドする必要があります。
それでは、何が問題なのか見てみましょう。

タイプ の純粋な関数がありInt -> Boolます。そして、明らかに純粋ではない(つまりIO Monadに存在する)デバッグ出力を出力したいとします。
とにかく、あなたが書きたいのはs.thです。それらの線に沿って:

foo x 
  | x > 0 = debug "ok" True
  | otherwise = debug "ohhh...no" False

それでも、関数のタイプはfoo :: Int -> Bool

debugそれでは、型チェッカーを満たす関数を定義しましょう。String (デバッグ メッセージ) と Bool (結果) を受け取り、Bool にのみ評価する必要があります。

debug :: String -> Bool -> Bool
debug = undefined

しかし、それを実装しようとすると、 putStrLn の型が であるため IO モナドをエスケープできないため、機能しませんputStrLn :: String -> IO ()。それを a への評価と組み合わせるには、 the ものコンテキストにBool入れる必要があります。BoolIO

debugIO msg result = putStrLn msg >> return result

では、この関数の型を ghci に聞いてみましょう:

Main> :t debugIO
debugIO :: String -> b -> IO b

したがって、 を取得しますIO Boolが、必要なのはBool.
タイプの関数はありIO b -> bますか?hoogleで簡単に調べると、ヒントが得られます。

悪名高いunsafePerformIO :: IO a -> aには、ここで必要なタイプがあります。
これで、関数を次のように実装できます。debugdebugIO

debug :: String -> Bool -> Bool
debug s r = unsafePerformIO $ debugIO s r

これは実際には、FUZxxl によって既に指摘されているようtraceに、パッケージ内の関数で得られるものとほぼ同じです。そして、関数の使用法を決して使用してはならないこと に同意するので、優先されます。純粋な型シグネチャであるにもかかわらず、実際には参照透過ではなく、その下で使用されることに注意してください。Debug.Trace
unsafePerformIOtraceunsafePerformIO

于 2011-10-04T17:27:05.290 に答える