Haskell使用$而不是括号是无效的

我是 Haskell 的新手。我想学习 $ 的用法,我写了两个小函数,但是第二个不起作用,有人可以解释一下那个小片段有什么问题吗?如果我理解正确,$ 就像括号一样工作。提前致谢 :)

myButLast::[a]->a
myButLast l = l !! (length l-2)

--not working
myButLast::[a]->a
myButLast l = l !! $ length l-2

回答

这不解析的原因True && || False与不解析相同:您使用了两个相邻的中缀运算符。编译器可能会用这样的东西做什么?

你可以这样写:

myButLast l = (l!!) $ length l-2

这意味着,将函数(l!!)应用于length l-2. 这是有效的,因为您可以部分应用任何 Haskell 函数,包括中缀运算符。但这反而违背了使用$避免括号的意义......

在一个有点不相关的注释上:length并且!!是 Haskell 中的代码异味。特别!!是既不安全又缓慢,使用它几乎从来都不是一个好主意。如果你真的需要这样的直接访问操作,你应该使用数组/向量(见下文),但为了至少安全,你可以更改签名:

myButLast :: [a] -> Maybe a
myButLast v = case length v of
 l | l>=2   -> Just . (v!!) $ l-1
 _ -> Nothing

请注意,在这种情况下,$确实有意义,因为它允许我将 RHS 和 LHS(函数Just(v!!)函数的组合)括起来。

同一件事的快速矢量版本:

import qualified Data.Vector.Generic as VG

myButLast :: VG.Vector v a => v a -> Maybe a
myButLast v = case VG.length v of
 l | l>=2   -> Just . VG.unsafeIndex v $ l-1
 _ -> Nothing


回答

如果我理解正确,$ 就像括号一样工作。

没有($) :: (a -> b) -> a -> b不是一些特殊的语法,它只是一个像 的运算符(+)(-)或者你自己定义的运算符。

这样做的原因是因为infixr 0优先级,这意味着该运算符的优先级最低,因此即使它们包含运算符,也会将左侧的元素分组在右侧,因为优先级会更高。

($) 本身实现为:

infixr 0  $

($) :: (a -> b) -> a -> b
($) f x = f x

因此它本质上是一个简单的函数应用程序,但运算符优先级让它看起来好像左右操作数有隐藏的括号。

您的表达式的问题在于它现在包含两个接一个的运算符,实际上:

myButLast l = l !! $ length l-2

所以这意味着解析器感到困惑。

您可以使用运算符分段并构造函数(l !!),然后使用运算符:

myButLast l = (l !!) $ length l-2
--              ↑ operator sectioning

但是最好不要length这里首先使用:通过使用 length 您将在列表上迭代两次:首先确定列表,然后获取最后一个索引。这是低效的,并且可能还会导致使用大量内存。

您可以通过以下方式简化此操作:

myButLast :: [a] -> a
myButLast (x:x2:xs) = go xs x x2
    where go [] y _ = y
          go (y2:ys) _ y = go ys y y2 
myButLast _ = error "empty list"


以上是Haskell使用$而不是括号是无效的的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>