我刚刚开始使用Haskell。
这个嵌套的where子句有什么问题?
length' a = fromIntegral (length a)
isPalin1 xs = fstHalf == reverse sndHalf
where
fstHalf = take halfLength xs
sndHalf = drop halfLength xs
where halfLength = (length' xs) / 2
我得到的错误:isPalin1.hs:5:32: Not in scope: ‘halfLength’
以下也是错误的,希望有人可以解释为什么:
length' a = fromIntegral (length a)
isPalin2 xs = fstHalf == reverse sndHalf
where
let
halfLength = (length' xs) / 2
in
fstHalf = take halfLength xs
sndHalf = drop halfLength xs
错误消息:
isPalin2.hs:7:17:
parse error (possibly incorrect indentation or mismatched brackets)
答案 0 :(得分:5)
正如评论中所提到的,对于isPalin1
,where
的范围是sndHalf
,而不是fstHalf
。我将重写isPalin1
示例(语法上)的方式如下:
isPalin1 xs = fstHalf == reverse sndHalf
where length' a = fromIntegral (length a)
halfLength = (length' xs) / 2
fstHalf = take halfLength xs
sndHalf = drop halfLength xs
这不会给你任何解析错误,并且范围都可以解决。但是,它不会编译,因为它的逻辑是关闭的。
问题是为什么你需要从整体?从查看代码的答案是,您正在尝试将列表拆分为一半,并且在尝试执行(length xs) / 2
之类的操作时可能会提前编译错误。看起来你要做的就是将列表分成两半,但这对于具有给定逻辑的奇数长度列表来说根本不起作用。如果列表的长度为11
,那么fstHalf
和sndHalf
应该是多少? (fromIntrgral (length xs)) / 2
会使halfLength
成为5.5
,但您无法从列表中获取5.5
个元素,因此Haskell的类型系统会混淆
除此之外,您可以使用(length xs) `div` 2
进行整数除法,丢弃余数。如果xs
的长度为10
,则会返回5
。如果xs
的长度为11
,则会返回5
。我不想给你一个完整的解决方案,以防这是一个家庭作业问题,但只要想想你如何使用整数除法来使你的程序工作。考虑一下长度为偶数或奇数的列表将如何影响确定它们是否为回文的算法,并使您的代码考虑到这一点。
至于你得到的第二个错误:原因是你有两个函数fstHalf
和sndHalf
位于let语句的in
子句中,导致解析错误。一般来说,我建议避免嵌套where
和if
语句,除非你绝对必须或者你是受虐狂。一个你清理逻辑,尝试坚持我在本文开头给出的示例where
语句的格式,它使事情变得更简单。
不要放弃Haskell,它会在你身上发展。 :)
答案 1 :(得分:5)
where
仅适用于一个绑定,因此您的第一个代码段中的halfLength
仅适用于sndHalf
。你应该这样写:
length' a = fromIntegral (length a)
isPalin1 xs = fstHalf == reverse sndHalf
where
halfLength = (length' xs) / 2
fstHalf = take halfLength xs
sndHalf = drop halfLength xs
这是因为where
本身就是一个范围,所以绑定可以互相引用。
至于你的第二个片段,这完全不正确。 let ⋯ in
语句严格来说是一个表达式,不能在where
的绑定上下文中使用。
如果你在哪里使用let ⋯ in
,你会像这样使用它:
length' a = fromIntegral (length a)
isPalin1 xs =
let halfLength = (length' xs) / 2
fstHalf = take halfLength xs
sndHalf = drop halfLength xs
in fstHalf == reverse sndHalf