2017-12-26 18 views
1

こんにちは、Haskellの初心者ここで:配列の関数のパターンはどのように見えますか?例えば:私は単に最初の要素に1を追加したい私の配列に関数のHaskell配列パターン

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

私はあなたが私の問題を理解してほしい:)

+2

配列を一致させることはできません。 Data.Arrayオンラインで文書化されている関数を調べます。 –

+0

'array'パッケージ内の不変の配列は、実際にそのように使うつもりはありません。不変配列は、高レベルの作成関数の1つを使用するか、 'STArray'または' IOArray'をフリーズすることによって、一度に "一度に"作成するのが最適です。作成後、通常は変更したくない場合があります。そうすることは、配列が大きい場合には非常に高価です。私は、実際に高性能の不変な配列のような構造のための、生産品質のHaskellライブラリは知らないが、近年いくつか有望な実験が行われている。 – dfeuer

答えて

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を処理する必要があります。ただし、にパブリック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) 

私は[]へとからの変換は、パフォーマンスのために、これは絶対にひどい作ることをかなり確信しています。