哈斯克尔嵌套在哪里子句和"让...在"语法



我刚开始使用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)

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

如注释中所述,对于isPalin1where的作用域为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

这不会给您带来任何解析错误,而且范围都是可行的。然而,它不会编译,因为你的逻辑已经关闭

问题是为什么需要fromIntegral?从代码中可以看出,答案是您正试图将列表一分为二,并且可能在早些时候尝试执行(length xs) / 2之类的操作时出现编译错误。看起来您要做的是将列表一分为二,但对于给定逻辑的奇数长度列表,这根本不起作用。如果列表的长度为11,那么fstHalfsndHalf应该是什么?(fromIntrgral (length xs)) / 2将使halfLength成为5.5,但不能从列表中获取5.5元素,因此Haskell的类型系统会混淆

相反,您可以使用(length xs) `div` 2进行整数除法,丢弃余数。如果xs的长度为10,则返回5。如果xs的长度为11,则返回5。如果这是一个家庭作业问题,我不想给你一个完整的解决方案,但只要想想如何使用整数除法使你的程序工作。考虑一下长度为偶数或奇数的列表将如何影响确定它们是否为回文的算法,并使您的代码考虑到这一点。

至于您得到的第二个错误:原因是您有两个函数fstHalfsndHalf,它们位于let语句的in子句中,从而导致解析错误。一般来说,我建议避免嵌套whereif语句,除非你绝对必须这样做,或者你是受虐狂。如果你理清了逻辑,试着坚持我在本文开头给出的示例where语句的格式,它会让事情变得简单得多。

不要放弃哈斯克尔,它会在你身上生长。:)

最新更新