Arrays 函数中的Haskell数组模式
Hi total Haskell初学者:数组函数中的模式是什么样的?例如:我只想向数组中的第一个元素添加+1Arrays 函数中的Haskell数组模式,arrays,haskell,pattern-matching,Arrays,Haskell,Pattern Matching,Hi total Haskell初学者:数组函数中的模式是什么样的?例如:我只想向数组中的第一个元素添加+1 > a = array (1,10) ((1,1) : [(i,( i * 2)) | i <- [2..10]]) 我希望您理解我的问题:)您无法在阵列上进行模式匹配,因为它没有任何数据构造函数公开。这是Haskell中的一种常见做法,因为它允许作者更新其数据类型的内部表示,而无需对其模块的用户进行重大更改 因此,使用阵列的唯一方法是使用模块提供的功能。要访问数组中的第一
> a = array (1,10) ((1,1) : [(i,( i * 2)) | i <- [2..10]])
我希望您理解我的问题:)您无法在阵列上进行模式匹配,因为它没有任何数据构造函数公开。这是Haskell中的一种常见做法,因为它允许作者更新其数据类型的内部表示,而无需对其模块的用户进行重大更改 因此,使用
阵列的唯一方法是使用模块提供的功能。要访问数组中的第一个值,可以使用边界
和(!)
的组合,或者从关联中获取第一个键/值对。然后可以使用(//)
对阵列进行更新
arraytest arr = arr // [(index, value + 1)]
where
index = fst (bounds arr)
value = arr ! index
如果选择使用assocs
,则可以根据其结果进行模式匹配:
arraytest arr = arr // [(index, value + 1)]
where
(index, value) = head (assocs arr) -- `head` will crash if the array is empty
或者,您可以使用列表和元组的Functor
实例:
arraytest arr = arr // take 1 (fmap (fmap (+1)) (assocs arr))
不过,您可能很快就会注意到,array
包缺少很多方便的函数。与操作在其他语言中的实现方式相比,上述所有解决方案都相当冗长
为了解决这个问题,我们有一个包(及其同类),它为Haskell添加了大量方便的函数,并使像array
这样的包更容易接受。这个软件包有一个相当陡峭的学习曲线,但它的使用非常普遍,绝对值得学习
import Control.Lens
arraytest arr = arr & ix (fst (bounds arr)) +~ 1
如果你眯起眼睛,你几乎可以看到它是怎么说的,arr[0]+=1
,但我们仍然没有牺牲任何不变性的好处。这更像是对@4castle答案的扩展评论。不能在数组上进行模式匹配,因为它的实现是隐藏的;您必须使用它的公共API来处理它们。但是,您可以使用公共API定义这样的模式(使用适当的语言扩展):
{-#语言模式同义词,视图模式#-}
--模式同义词:定义模式而不实际定义类型
--ViewPatterns:构造应用函数和匹配子模式的模式
进口管制。箭头(&&&&))——完全是为了躲避丑陋的羔羊;如果你愿意的话
阵列::ixi=>(i,i)->[(i,e)]->阵列ie
--类型签名提示这是数组函数,但是双向的
阵列边界'assocs'(边界'assocs'))
--在与数组边界“assocs”匹配时,将边界&&&assocs应用于
--传入数组,并将结果元组匹配到(bounds',assocs')
其中Array=Array
--在表达式中使用数组与仅使用数组相同
数组测试(数组bs((i,x):xs))=数组bs((i,x+1):xs)
我相当肯定,与[]
之间的转换会使性能变得非常糟糕。您无法对阵列进行模式匹配。在线查找Data.Array中记录的函数。Array
包中的不可变数组实际上并不打算这样使用。最好使用一个高级创建函数或冻结STArray
或IOArray
来“一次性”创建不可变数组。一旦它被创建,你通常不想修改它;如果阵列很大,那么这样做的成本相当高。我不知道有哪种产品质量的Haskell库可以用于真正高性能的不可变数组结构,但近年来已经有了一些很有希望的实验。
import Control.Lens
arraytest arr = arr & ix (fst (bounds arr)) +~ 1
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
-- PatternSynonyms: Define patterns without actually defining types
-- ViewPatterns: Construct patterns that apply functions as well as match subpatterns
import Control.Arrow((&&&)) -- solely to dodge an ugly lambda; inline if you wish
pattern Array :: Ix i => (i, i) -> [(i, e)] -> Array i e
-- the type signature hints that this is the array function but bidirectional
pattern Array bounds' assocs' <- ((bounds &&& assocs) -> (bounds', assocs'))
-- When matching against Array bounds' assocs', apply bounds &&& assocs to the
-- incoming array, and match the resulting tuple to (bounds', assocs')
where Array = array
-- Using Array in an expression is the same as just using array
arraytest (Array bs ((i,x):xs)) = Array bs ((i,x+1):xs)