在 Haskell 中,'@' 的含义是什么?

11

我曾经试着谷歌搜索,但是没有找到相关信息。我正在通过阅读一些文章来进一步学习Haskell知识,然后我遇到了一个使用我从未见过语法的例子。

reconstruct node@(Node a b c l r) parent@(Node b d le ri)

我以前从未见过这些@符号。我尝试在网上搜索答案,但没有找到。这只是一种嵌入标签以帮助使事情更清晰的方法,还是它们对代码有实际影响?


1
在 http://learnyouahaskell.com/syntax-in-functions#pattern-matching 中搜索“as patterns”以获取介绍。 - jub0bs
8
传统搜索引擎在搜索特殊字符时无法返回有用的结果,但Haskell自带的hoogle通常非常有用于此类问题。 - ComicSansMS
@ComicSansMS 比答案更有帮助! - Dmitri Zaitsev
这个回答解决了你的问题吗?理解Haskell中的as-pattern - Redu
@ComicSansMS,但对于搜索语法并没有帮助。 - dfeuer
2个回答

23

它用于模式匹配。现在,node 变量将引用参数 Node a b c l r 的整个 Node 数据类型。因此,您可以使用 node 代替传递给函数的 Node a b c l r

下面是一个更简单的示例来演示它:

data SomeType = Leaf Int Int Int | Nil deriving Show

someFunction :: SomeType -> SomeType
someFunction leaf@(Leaf _ _ _) = leaf
someFunction Nil = Leaf 0 0 0

someFunction也可以写成:

someFunction :: SomeType -> SomeType
someFunction (Leaf x y z) = Leaf x y z
someFunction Nil = Leaf 0 0 0

看看第一个版本是多么简单?


更简单的方法是 someFunction leaf@Leaf{} = leaf - András Kovács
2
@AndrásKovács,但是这不需要对Leaf{}进行一些解释吗? - d12frosted
1
终于搞清楚需要 {-# LANGUAGE TypeApplications #-},不过还在学习它是什么。 - Josh.F
1
@jpmarinier,不,它不是任何类型转换。它确实允许您应用类型参数,但这些参数的含义取决于涉及的特定函数或方法。 - dfeuer
1
@jpmarinier,它非常松散,我甚至猜不出它的含义。foo @Int很容易是一个函数,它接受两个字符并生成一个返回 ()IO 操作。 - dfeuer
显示剩余4条评论

12

使用@t作为类型指示器

除了 @Sibi 的答案中描述的参数模式匹配用法之外,在 Haskell 中,“at”字符('@',也称为 艾特符号)可以在某些情况下用于强制类型决策。这是由 @Josh.F. 在评论中提到的。

不是默认语言功能的一部分,而是已知的类型应用 Haskell 语言扩展。简而言之,该扩展允许您向多态函数(如 read)提供显式类型参数。在经典的 .hs 源文件中,相关的 pragma 必须被包含:

{-#  LANGUAGE TypeApplications  #-}

示例:

$ ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
 λ> 
 λ> let x = (read @Integer "33")

 <interactive>:4:10: error:
    Pattern syntax in expression context: read@Integer
    Did you mean to enable TypeApplications?
 λ> 
 λ> :set -XTypeApplications
 λ>
 λ> let x = (read @Integer "33")
 λ>
 λ> :type  x
 x :: Integer
 λ> 
 λ> x
 33
 λ> 

更多细节

对于多态函数read,由@引入的类型指示符与read返回的结果类型相关。但这通常不是如此。

一般来说,您必须考虑出现在手头函数的类型签名中的类型变量。例如,让我们看看fmap库函数。

fmap :: Functor ft => (a -> b) -> ft a -> ft b

在这里,我们有三个类型变量,按出现顺序为:ft、a、b。如果我们像这样专门化fmap

myFmap = fmap  @type1  @type2  @type3

那么type1将与ft相关联,type2将与a相关联,type3将与b相关联。还有一个特殊的虚拟类型指示器@_,表示:“这里可以是任何类型”。
例如,我们可以强制fmap的输出类型为Integer,将函子设置为普通列表[],留下输入类型a未指定。
 λ> 
 λ> myFmap = fmap  @[]  @_  @Integer
 λ> 
 λ> :type myFmap
 myFmap :: (_ -> Integer) -> [_] -> [Integer]
 λ> 

关于read函数,它的类型是:

read :: Read a => String -> a

因此,只有一个类型指示器的空间,它与read返回的结果类型相关,如上所示。


这正是我在寻找的 - 我知道@符号在模式匹配中的用法,但不知道它可以用于类型指示。谢谢! - Brent Pappas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接