函数中的Haskell数组模式

问题描述 投票:1回答:2

嗨,总Haskell初学者:数组函数中的模式是什么样的?例如:我只想为我的数组中的第一个元素添加+1

> a = array (1,10) ((1,1) : [(i,( i * 2)) | i <- [2..10]])

我的第一个想法是:

> arraytest :: Array (Int,Int) Int -> Array (Int,Int) Int
> arraytest (array (mn,mx) (a,b):xs) = (array (mn,mx) (a,b+1):xs)

我希望你理解我的问题:)

arrays haskell pattern-matching
2个回答
4
投票

您无法在数组上进行模式匹配,因为the data declaration in the Data.Array.IArray module for the Array type没有公开任何数据构造函数。这是Haskell中的常见做法,因为它允许作者更新其数据类型的内部表示,而不会对其模块的用户进行重大更改。

因此,使用Array的唯一方法是使用模块提供的功能。要访问数组中的第一个值,可以使用bounds(!)的组合,或者从assocs获取第一个键/值对。然后你可以使用(//)来更新数组。

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包装缺少许多便利功能。与在其他语言中实现操作的方式相比,上述所有解决方案都相当冗长。

为了解决这个问题,我们有了lens软件包(以及它的堂兄弟),它为Haskell添加了大量的便利功能,并使像array这样的软件包更加可以忍受。这个包有一个相当陡峭的学习曲线,但它非常普遍使用,绝对值得学习。

import Control.Lens

arraytest arr = arr & ix (fst (bounds arr)) +~ 1

如果你眯着眼睛,你几乎可以看到它如何说arr[0] += 1,但我们仍然没有牺牲不变性的任何好处。


1
投票

这更像是对@ 4castle答案的延伸评论。你不能在Array上模式匹配,因为它的实现是隐藏的;您必须使用其公共API来使用它们。但是,您可以使用公共API来定义此类模式(使用适当的语言扩展名):

{-# 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)

我很确定来往[]的转换使得这对于性能来说非常糟糕。

© www.soinside.com 2019 - 2024. All rights reserved.