`(整数a)=> a - > Bool`和`整数 - > Bool`之间的区别?

Naw*_*waz 4 haskell function purely-functional

我今天在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
Run Code Online (Sandbox Code Playgroud)

它很棒.但我怀疑的是,第一行是许多命中和试验的结果,因为我在本教程中读到的内容不起作用,并且给出了这个错误(我这是一个错误,尽管它没有这么说):

prime.hs:9:13:
    Type constructor `Integer' used as a class
    In the type signature for `is_prime':
      is_prime :: Integer a => a -> Bool
Run Code Online (Sandbox Code Playgroud)

根据教程(顺便说一下,这是一个编写得很好的教程(Integral a) => a -> String(Integer a) => a -> Bool),第一行应该是:( 教程说,所以我认为应该也可以.)

is_prime :: (Integer a) => a -> Bool
Run Code Online (Sandbox Code Playgroud)

哪个不起作用,并给出上面发布的错误(?).

为什么它不起作用?这一行(不起作用)和行(起作用)有什么区别?


此外,什么是通过惯用的方式来循环1N?我对代码中的循环并不完全满意.请提出改进​​建议.这是我的代码:

--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
Run Code Online (Sandbox Code Playgroud)

dav*_*420 13

你误读了这个教程.它会说类型签名应该是

is_prime :: (Integral a) => a -> Bool
--       NOT Integer a
Run Code Online (Sandbox Code Playgroud)

这些是不同的类型:

  • Integer -> Bool
    • 这是一个采用类型值Integer并返回类型值的函数Bool.
  • Integral a => a -> Bool
    • 这是一个采用类型值a并返回类型值的函数Bool.
    • 什么是a?它可以是实现Integral类型类的任何类型的调用者选择,例如IntegerInt.

(IntInteger?之间的区别?后者可以表示任何大小的整数,前者最终包裹,类似于intC/Java /等中的s.)


循环的惯用方法取决于循环的作用:它可以是地图,折叠或过滤器.

你的循环main是一个地图,因为你在循环中进行i/o,你需要使用mapM_.

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

同时,你的循环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
Run Code Online (Sandbox Code Playgroud)

(并且在一个小的风格点上,在Haskell中使用名称isPrime而不是像is_prime.这样的名称.)


Die*_*Epp 5

第1部分:如果再次查看教程,您会注意到它实际上以下列形式提供了类型签名:

isPrime :: Integer -> Bool
-- or
isPrime :: Integral a => a -> Bool
isPrime :: (Integral a) => a -> Bool -- equivalent
Run Code Online (Sandbox Code Playgroud)

这里Integer是具体类型的名称(具有实际表示),并且Integral是类的类型的名称.该Integer类型是Integral该类的成员.

约束Integral a意味着无论a发生什么类型,a都必须是Integral类的成员.

第2部分:有很多方法可以编写这样的函数.您的递归定义看起来很好(尽管您可能希望使用n < i * i而不是n < 2 * i,因为它更快).

如果你正在学习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))
Run Code Online (Sandbox Code Playgroud)