Haskell 递减函数
Haskell decrement function
我正在尝试学习 Haskell,这是我在函数式编程方面的第一个方法。我在创建一个将数字作为输入并递归地逐一打印该数字直到 0 的函数时遇到了一些问题。
printDescending n = if n > 0
then printDescending n - 1 return n
else return n - 1
我希望能够执行 printDescending 20
并让它输出 20、19、18...2、1、0。但我收到此错误:
> • Non type-variable argument
> in the constraint: Num ((a -> m a) -> a1 -> m1 a1)
> (Use FlexibleContexts to permit this)
> • When checking the inferred type
> printDescending :: forall (m :: * -> *) a (m1 :: * -> *) a1.
> (Ord a1, Num ((a -> m a) -> a1 -> m1 a1), Num (m1 a1), Num a1,
> Monad m1, Monad m) =>
> a1 -> m1 a1 Failed, modules loaded: none.
我想这可能是我的语法问题。有人有一些见解吗?
您已经显示:
printDescending n = if n > 0
then printDescending n - 1 return n
else return n - 1
让我们先看看这是如何解析的:
printDescending n = if n > 0
then (printDescending n) - (1 return n)
else (return n) - 1
可能不是您想要的,是吧?请注意中缀运算符,例如 -
绑定不如函数应用程序紧密。另请参阅 'return' 并不特别 - 它也只是函数应用程序。最后,您实际上并没有包含对任何类型的 print
命令的调用,因此无论您使用哪种语言,我都不希望它起作用。
解决这些问题,让我们首先提供一个类型签名(有点像 C 中的函数原型):
printDescending :: Int -> IO ()
所以 printDecending
接受一个参数,一个 Int
,并做一些 IO。 ()
被称为 "unit" 并且对于了解 C 的程序员的第一课,您应该能够在心理上将其视为 void
并且没问题。
现在 body 怎么样?那么你的 if
陈述很好:
printDescending n =
if n > 0
then ...
else...
else
声明有点奇怪。即使修复了解析,你为什么要0-1
?让我们只是 return 单位:
printDescending n =
if n > 0
then ...
else return ()
现在对于 then
分支,您确实需要两件事。 1. 打印值 2. 对下一个最小值递归调用 printDecending。有一种符号,do
,我们将使用它来对两个 IO 操作进行排序,但除此之外,这两个任务直接转换为命令:
printDescending n =
if n > 0
then do print n
printDescending (n - 1)
else return ()
现在让我们再做一步。由于这不是 C/Java/etc 并且是一种函数式语言,因此人们会期待一种声明式的风格。为此,让我们使用 guards 而不是 if 语句来声明 printDescending:
printDescending n
| n > 0 = do print n
printDescending (n-1)
| otherwise = return ()
备选方案
现在我将介绍一些替代方案,仅作为示例。
如果您不关心负值,那么我们可以在零处终止,例如:
printDescending 0 = return ()
printDescending n =
do print n
printDescending (n-1)
或者我们可以使用列表理解来构建值列表,然后对列表的每个元素执行 print
。我们可以用 forM_
来做到这一点(另见更惯用的 mapM_
),它对列表的每个元素执行一个操作并丢弃结果,returning unit.
printDescending n = forM_ [n,n-1..1] print
最后,如果您想进行更快速的交流,请考虑加入 irc.freenode.net 上的#haskell 频道。那里有一个很棒的团队,我认识的许多 Haskell 程序员都是从那里开始的。
除了 Thomas 的详细回答外,我觉得以下是您想要的:
printDescending :: Integer -> IO ()
printDescending n = do
print n
if n > 0
then printDescending (n - 1)
else return ()
诚然,return ()
一开始可能看起来很奇怪。
更实用的方法可能是这样的:
printDescending :: Integer -> IO ()
printDescending n = mapM_ print [n, (n-1) .. 0]
快速提示:我建议添加函数签名(如果您知道它是什么),因为它有助于指导编译器的错误消息。
我正在尝试学习 Haskell,这是我在函数式编程方面的第一个方法。我在创建一个将数字作为输入并递归地逐一打印该数字直到 0 的函数时遇到了一些问题。
printDescending n = if n > 0
then printDescending n - 1 return n
else return n - 1
我希望能够执行 printDescending 20
并让它输出 20、19、18...2、1、0。但我收到此错误:
> • Non type-variable argument
> in the constraint: Num ((a -> m a) -> a1 -> m1 a1)
> (Use FlexibleContexts to permit this)
> • When checking the inferred type
> printDescending :: forall (m :: * -> *) a (m1 :: * -> *) a1.
> (Ord a1, Num ((a -> m a) -> a1 -> m1 a1), Num (m1 a1), Num a1,
> Monad m1, Monad m) =>
> a1 -> m1 a1 Failed, modules loaded: none.
我想这可能是我的语法问题。有人有一些见解吗?
您已经显示:
printDescending n = if n > 0
then printDescending n - 1 return n
else return n - 1
让我们先看看这是如何解析的:
printDescending n = if n > 0
then (printDescending n) - (1 return n)
else (return n) - 1
可能不是您想要的,是吧?请注意中缀运算符,例如 -
绑定不如函数应用程序紧密。另请参阅 'return' 并不特别 - 它也只是函数应用程序。最后,您实际上并没有包含对任何类型的 print
命令的调用,因此无论您使用哪种语言,我都不希望它起作用。
解决这些问题,让我们首先提供一个类型签名(有点像 C 中的函数原型):
printDescending :: Int -> IO ()
所以 printDecending
接受一个参数,一个 Int
,并做一些 IO。 ()
被称为 "unit" 并且对于了解 C 的程序员的第一课,您应该能够在心理上将其视为 void
并且没问题。
现在 body 怎么样?那么你的 if
陈述很好:
printDescending n =
if n > 0
then ...
else...
else
声明有点奇怪。即使修复了解析,你为什么要0-1
?让我们只是 return 单位:
printDescending n =
if n > 0
then ...
else return ()
现在对于 then
分支,您确实需要两件事。 1. 打印值 2. 对下一个最小值递归调用 printDecending。有一种符号,do
,我们将使用它来对两个 IO 操作进行排序,但除此之外,这两个任务直接转换为命令:
printDescending n =
if n > 0
then do print n
printDescending (n - 1)
else return ()
现在让我们再做一步。由于这不是 C/Java/etc 并且是一种函数式语言,因此人们会期待一种声明式的风格。为此,让我们使用 guards 而不是 if 语句来声明 printDescending:
printDescending n
| n > 0 = do print n
printDescending (n-1)
| otherwise = return ()
备选方案
现在我将介绍一些替代方案,仅作为示例。
如果您不关心负值,那么我们可以在零处终止,例如:
printDescending 0 = return ()
printDescending n =
do print n
printDescending (n-1)
或者我们可以使用列表理解来构建值列表,然后对列表的每个元素执行 print
。我们可以用 forM_
来做到这一点(另见更惯用的 mapM_
),它对列表的每个元素执行一个操作并丢弃结果,returning unit.
printDescending n = forM_ [n,n-1..1] print
最后,如果您想进行更快速的交流,请考虑加入 irc.freenode.net 上的#haskell 频道。那里有一个很棒的团队,我认识的许多 Haskell 程序员都是从那里开始的。
除了 Thomas 的详细回答外,我觉得以下是您想要的:
printDescending :: Integer -> IO ()
printDescending n = do
print n
if n > 0
then printDescending (n - 1)
else return ()
诚然,return ()
一开始可能看起来很奇怪。
更实用的方法可能是这样的:
printDescending :: Integer -> IO ()
printDescending n = mapM_ print [n, (n-1) .. 0]
快速提示:我建议添加函数签名(如果您知道它是什么),因为它有助于指导编译器的错误消息。