我今天在Haskell写了我的第一个程序 . It compiles and runs successfully . 而且由于它不是典型的"Hello World"程序,它实际上远不止于此,所以请恭喜我:D
无论如何,我对我的代码和Haskell中的语法几乎没有疑问 .
Problem:
我的程序从标准输入读取整数 N
,然后,对于 [1,N]
范围内的每个整数 i
,它打印 i
是否为素数 . 目前它不检查输入错误 . :-)
Solution: (也是疑惑/问题)
为了解决这个问题,我编写了这个函数来测试整数的素数:
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
它很棒 . 但我怀疑是第一行是许多命中和试验的结果,因为我在this tutorial中读到的内容不起作用,并且给出了这个错误(我想这是一个错误,尽管它没有这么说) :
prime.hs:9:13:
Type constructor `Integer' used as a class
In the type signature for `is_prime':
is_prime :: Integer a => a -> Bool
根据the tutorial(顺便说一下,这是一个编写得很好的教程),第一行应该是:(教程说 (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
3 回答
你误读了这个教程 . 它会说类型签名应该是
这些是不同的类型:
Integer -> Bool
这是一个函数,它取一个
Integer
类型的值,并返回一个Bool
类型的值 .Integral a => a -> Bool
这是一个函数,它采用
a
类型的值并返回Bool
类型的值 .什么是
a
?它可以是实现Integral
类型类的任何类型的调用者选择,例如Integer
或Int
.(和
Int
和Integer
之间的区别?后者可以表示任何大小的整数,前者最终包围,类似于C / Java /等中的int
. )循环的惯用方法取决于循环的作用:它可以是 Map ,折叠或过滤器 .
你在
main
中的循环是一个 Map ,因为你在循环中进行i / o,你需要使用mapM_
.同时,你在
is_prime
的循环是一个折叠(在这种情况下特别是all
):(在一个小的风格点上,在Haskell中使用
isPrime
之类的名称而不是像is_prime
这样的名称是常规的 . )Part 1: 如果再次查看教程,您会注意到它实际上以下列形式提供了类型签名:
这里,
Integer
是具体类型的名称(具有实际表示),Integral
是类类的名称 .Integer
类型是Integral
类的成员 .约束
Integral a
意味着无论a
类型是什么类型,a
必须是Integral
类的成员 .Part 2: 有很多方法可以编写这样的功能 . 您的递归定义看起来很好(尽管您可能希望使用
n < i * i
而不是n < 2 * i
,因为它更快) .如果你正在学习Haskell,你可能想尝试使用高阶函数或列表推导来编写它 . 就像是:
这是
Integral a
,而不是Integer a
. 见http://www.haskell.org/haskellwiki/Converting_numbers .map
和朋友们是如何在Haskell中循环的 . 这就是我重写循环的方法: