12

我试过用谷歌搜索,但结果很短。我通过阅读一些文章来加深我的 Haskell 知识,我遇到了一篇使用我以前从未见过的语法的文章。一个例子是:

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

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

4

2 回答 2

22

它用于模式匹配。现在node变量将引用参数的整个Node数据类型Node a b c l rNode 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

看看第一个版本有多简单?

于 2015-05-19T12:59:28.440 回答
11

使用@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将涉及到fttype2将涉及到atype3将涉及到b。此外,还有一个特殊的虚拟类型指示器@_,意思是:“<em>这里,任何类型都可以”。

例如,我们可以强制 的输出类型为fmapInteger函子为普通列表[],不指定输入类型a

 λ> 
 λ> myFmap = fmap  @[]  @_  @Integer
 λ> 
 λ> :type myFmap
 myFmap :: (_ -> Integer) -> [_] -> [Integer]
 λ> 

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

read :: Read a => String -> a

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

于 2019-11-09T16:32:28.593 回答