我试过用谷歌搜索,但结果很短。我通过阅读一些文章来加深我的 Haskell 知识,我遇到了一篇使用我以前从未见过的语法的文章。一个例子是:
reconstruct node@(Node a b c l r) parent@(Node b d le ri)
我以前从未见过这些@。我尝试在网上搜索答案,但没有找到答案。这仅仅是一种嵌入标签以帮助使事情更清晰的方法,还是它们对代码有实际影响?
它用于模式匹配。现在node
变量将引用参数的整个Node
数据类型Node a b c l r
。Node a b c l r
因此,您可以使用而不是传递给函数 as ,node
而是将其传递。
一个更简单的示例来演示它:
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
看看第一个版本有多简单?
除了@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
。此外,还有一个特殊的虚拟类型指示器@_
,意思是:“<em>这里,任何类型都可以”。
例如,我们可以强制 的输出类型为fmap
,Integer
函子为普通列表[]
,不指定输入类型a
:
λ>
λ> myFmap = fmap @[] @_ @Integer
λ>
λ> :type myFmap
myFmap :: (_ -> Integer) -> [_] -> [Integer]
λ>
至于read
函数,它的类型是:
read :: Read a => String -> a
所以只有一个类型指标的空间,它与返回的结果的类型有关read
,如上所示。