4

今日、Haskell で最初のプログラムを書きました。正常にコンパイルおよび実行されます。そして、これは典型的な「Hello World」プログラムではないため、実際にはそれ以上のことを行うので、よろしくお願いします :D

とにかく、自分のコードと Haskell の構文に関しては、ほとんど疑いがありません。

問題:

N私のプログラムは、標準入力から整数を読み取り、i範囲内の各整数について、 が素数[1,N]かどうかを出力します。i現在、入力エラーのチェックは行っていません。:-)

解決策:(疑問/質問も)

この問題を解決するために、整数の素数性をテストする次の関数を作成しました。

is_prime :: Integer -> Bool
is_prime n = helper n 2
        where
          helper :: Integer -> Integer -> Bool
          helper n i  
              | n < 2 * i = True
              | mod n i > 0 = helper n (i+1)
              | otherwise = False

それはうまくいきます。しかし、このチュートリアルで読んだことが機能せず、このエラーが発生したため、最初の行は多くの試行錯誤の結果であるとは思えません (そうは言っていませんが、これはエラーだと思います) ):

prime.hs:9:13:
    Type constructor `Integer' used as a class
    In the type signature for `is_prime':
      is_prime :: Integer a => a -> Bool

チュートリアル(ちなみに、これはよくできたチュートリアルです) によると、最初の行は次のよう(Integral a) => a -> String(Integer a) => a -> Boolになります

is_prime :: (Integer a) => a -> Bool

これは機能せず、上記の投稿されたエラー (?) が表示されます。

そして、なぜそれが機能しないのですか?この行 (機能しない) と行 (機能する) の違いは何ですか?


1また、にループする慣用的な方法は何Nですか? コード内のループに完全に満足していません。改善を提案してください。これが私のコードです:

--read_int function
read_int :: IO Integer
read_int = do
     line <- getLine
     readIO line

--is_prime function
is_prime :: Integer -> Bool
is_prime n = helper n 2
        where
          helper :: Integer -> Integer -> Bool
          helper n i  
              | n < 2 * i = True
              | mod n i > 0 = helper n (i+1)
              | otherwise = False

main = do
       n <- read_int
       dump 1 n
       where
           dump i x = do 
                 putStrLn ( show (i) ++ " is a prime? " ++ show (is_prime i) )
                 if i >= x 
                    then putStrLn ("")
                  else do
                    dump (i+1) x
4

3 に答える 3

13

チュートリアルを読み間違えています。型署名は次のようになります

is_prime :: (Integral a) => a -> Bool
--       NOT Integer a

これらは異なるタイプです:

  • Integer -> Bool
    • これは、typeの値を受け取り、typeIntegerの値を返す関数ですBool
  • Integral a => a -> Bool
    • これは、typeの値を受け取り、typeaの値を返す関数ですBool
    • aですか?またはIntegralなど、型クラスを実装する呼び出し元の選択の任意のタイプにすることができます。IntegerInt

Int(そして、との違いはInteger?後者は任意の大きさの整数を表すことができ、前者intはC / Javaなどのsと同様に、最終的にラップアラウンドします。)


ループする慣用的な方法は、ループの動作によって異なります。マップ、フォールド、またはフィルターのいずれかになります。

ループインmainはマップであり、ループ内でI / Oを実行しているため、を使用する必要がありますmapM_

let dump i = putStrLn ( show (i) ++ " is a prime? " ++ show (is_prime i) )
 in mapM_ dump [1..n]

その間、ループインis_primeはフォールドです(特にallこの場合):

is_prime :: Integer -> Bool
is_prime n = all nondivisor [2 .. n `div` 2]
        where
          nondivisor :: Integer -> Bool
          nondivisor i = mod n i > 0

(そして、スタイルのマイナーな点で、Haskellではのような名前のisPrime代わりにのような名前を使用するのが一般的is_primeです。)

于 2012-06-30T17:01:23.300 に答える
5

パート1:チュートリアルをもう一度見ると、実際には次の形式で型署名が付けられていることがわかります。

isPrime :: Integer -> Bool
-- or
isPrime :: Integral a => a -> Bool
isPrime :: (Integral a) => a -> Bool -- equivalent

ここで、Integerは具象型の名前(実際の表現があります)でありIntegral、型のクラスの名前です。IntegerタイプはIntegralクラスのメンバーです。

制約Integral aは、どのタイプであっても、クラスのメンバーでなければならaないことを意味します。aIntegral

パート2:そのような関数を書く方法はたくさんあります。再帰的定義は問題ないように見えます(ただし、より高速であるため、のn < i * i代わりに使用することをお勧めしますn < 2 * i)。

Haskellを学んでいる場合は、高階関数またはリスト内包表記を使用してHaskellを作成してみてください。何かのようなもの:

module Main (main) where
import Control.Monad (forM_)

isPrime :: Integer -> Bool
isPrime n = all (\i -> (n `rem` i) /= 0) $ takeWhile (\i -> i^2 <= n) [2..]

main :: IO ()
main = do n <- readLn
          forM_ [1..n] $ \i ->
              putStrLn (show (i) ++ " is a prime? " ++ show (isPrime i))
于 2012-06-30T17:01:22.463 に答える
3
  1. ではIntegral aなくInteger aです。http://www.haskell.org/haskellwiki/Converting_numbersを参照してください。

  2. mapと友達はあなたがHaskellでループする方法です。これは私がループを書き直す方法です:

    main :: IO ()
    main = do
            n <- read_int
            mapM_ tell_prime [1..n]
            where tell_prime i = putStrLn (show i ++ " is a prime? " ++ show (is_prime i))
    
于 2012-06-30T16:59:19.867 に答える