Haskell 中的“@”是什么意思?
What does '@' mean in Haskell?
我试过谷歌搜索,但没有找到答案。我通过阅读一些文章来进一步扩展我的 Haskell 知识,并且我遇到了一篇使用我以前从未见过的语法的文章。
一个例子是:
reconstruct node@(Node a b c l r) parent@(Node b d le ri)
我以前从未见过这些@。我试着在网上搜索答案,但没有找到答案。这仅仅是一种嵌入标记以帮助使事情更清晰的方法,还是它们对代码有实际影响?
用于模式匹配。现在 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
看看第一个版本有多简单?
使用@t 作为类型指示符
除了@Sibi 的回答中描述的参数模式匹配用法外,在Haskell中可以使用“at”字符('@',也称为arobase字符)某些上下文强制输入决定。 @Josh.F.
的评论中提到了这一点
这 不是 默认语言功能的一部分,被称为 Type Application Haskell 语言扩展。总之,该扩展允许您为多态函数提供显式类型参数,例如 read
。在经典的 .hs 源文件中,必须包含相关的编译指示:
{-# 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
所以在这里,我们有 3 个类型变量,按出现顺序排列: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
返回结果的类型有关,如上所示。
我试过谷歌搜索,但没有找到答案。我通过阅读一些文章来进一步扩展我的 Haskell 知识,并且我遇到了一篇使用我以前从未见过的语法的文章。 一个例子是:
reconstruct node@(Node a b c l r) parent@(Node b d le ri)
我以前从未见过这些@。我试着在网上搜索答案,但没有找到答案。这仅仅是一种嵌入标记以帮助使事情更清晰的方法,还是它们对代码有实际影响?
用于模式匹配。现在 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
看看第一个版本有多简单?
使用@t 作为类型指示符
除了@Sibi 的回答中描述的参数模式匹配用法外,在Haskell中可以使用“at”字符('@',也称为arobase字符)某些上下文强制输入决定。 @Josh.F.
的评论中提到了这一点这 不是 默认语言功能的一部分,被称为 Type Application Haskell 语言扩展。总之,该扩展允许您为多态函数提供显式类型参数,例如 read
。在经典的 .hs 源文件中,必须包含相关的编译指示:
{-# 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
所以在这里,我们有 3 个类型变量,按出现顺序排列: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
返回结果的类型有关,如上所示。