2011-09-27 9 views

答えて

13

はい、ViewPatterns拡張子を使用できます。

Prelude> :set -XViewPatterns 
Prelude> let f (last -> x) = x*2 
Prelude> f [1, 2, 3] 
6 

このパターンはいつもあなたは、おそらくリストが空である場合のパターンを追加したいと思うので、他のlastは、例外がスローされます、しかし、成功することに注意してください。

Prelude> f [] 
*** Exception: Prelude.last: empty list 

これは単なる構文的な砂糖です。通常のパターンマッチングとは異なり、これはO(n)です。これは、依然として単一リンクリストの最後の要素にアクセスしているためです。より効率的なアクセスが必要な場合は、Data.Sequenceなどの異なるデータ構造を使用することを検討してください。O(1)の両端にアクセスできます。

+0

最後に空のリストで例外がスローされます。私は最後から頭を離れることを目指しています、頭、fst、snd。空リストをうまく扱えない関数。パターンマッチング、let(x:xs)= "abcdefg"などは、私の質問で言及したものです。安全でないプレリュード関数を使用せずに、最後の要素を得るための同様のアプローチが必要であると考えていました。 –

+2

@MichaelLitchard:まあ、あなたは 'Maybe'を返す' safeLast'関数を定義することができます。この関数はパターンマッチやリストを逆順にして通常のパターンマッチングを使うことができます。 – hammar

+2

それは常に成功するので、「パターンマッチ」はあまりありません。 'f =(* 2)。最後は良いです。 – u0b34a0f6ae

11

あなたは

printLast :: Show a => IO() 
printLast (reverse -> (x:_)) = print x 
printLast _ = putStrLn "Sorry, there wasn't a last element to print." 
例えば、リストの最後にパターンマッチングを行うために ViewPatternsを使用して、それでは

{-# LANGUAGE ViewPatterns #-} 

を行うと、それは常に成功しているため、viewFunctionとしてreverseを使用してみましょう、そうすることができます

これは、すべての可能性をカバーする限り、例外をスローしないという意味では安全です。あなただけの、実際にそれを見ることができるように (あなたがたとえば、Maybeを返すように書き換えることができます。)

構文

mainFunction (viewFunction -> pattern) = resultExpression

mainFunction x = case viewFunction x of pattern -> resultExpression

ためのシンタックスシュガーでありますリストを逆にしてパターンをマッチさせますが、それはより良い感じです。 viewFunctionは、好きな機能に過ぎません。 (延長の目的の一つは、彼らが がそれに関数を定義するときにそのデータ型の基本構造を使用する必要はありませんでしたので、人々はきれいにし、簡単にパターンマッチングのためのアクセサ関数 を使用できるようにすることでした。)

4

その他の回答は、ViewPatternsベースのソリューションについて説明しています。

tailLast :: [a] -> Maybe ([a], a) 
tailLast [email protected](_:_) = Just (init xs, last xs) 
tailLast _ = Nothing 

pattern Split x1 xs xn = x1 : (tailLast -> Just (xs, xn)) 

をして、例えばとしてあなたの関数を書く:あなたはそれがより多くのパターンマッチングのようにしたい場合は、PatternSynonymにそれをパッケージ化することができます

foo :: [a] -> (a, [a], a) 
foo (Split head mid last) = (head, mid, last) 
foo _ = error "foo: empty list" 
2

これはHaskellのプログラミングの私の最初の日であり、私も同じ問題に遭遇しましたが、私は、以前のソリューションで示唆されているように、外部アーティファクトのいくつかの種類を使用することを解決できませんでした。

ハスケルについての私の気持ちは、コア言語があなたの問題の解決策を持たないならば、その解決策は言語のために働くまであなたの問題を変えることです。

この場合、問題を変換するということは、テールの問題を頭の問題に変換することを意味します。これはパターンマッチングで唯一サポートされているようです。リスト逆変換を使って簡単に行うことができ、元のリストのtail要素を使用するようにhead要素を使用して逆のリストを処理し、最後に結果を元の順序に戻すことができます(ifそれはリストでした)。

たとえば、整数のリスト(たとえば[1,2,3,4,5,6])が与えられた場合、このリストを作成して、元のリストの最後から2番目の要素その二重に置き換えられます(Homework1からthis excellent introduction to Haskellの運動):[2,2,6,4,10,6]。

その後、我々は次のように使用することができます。

revert :: [Integer] -> [Integer] 
revert []  = [] 
revert (x:[]) = [x] 
revert (x:xs) = (revert xs) ++ [x] 

doubleSecond :: [Integer] -> [Integer] 
doubleSecond []  = [] 
doubleSecond (x:[]) = [x] 
doubleSecond (x:y:xs) = (x:2*y : (doubleSecond xs)) 

doubleBeforeLast :: [Integer] -> [Integer] 
doubleBeforeLast l = (revert (doubleSecond (revert l))) 

main = putStrLn (show (doubleBeforeLast [1,2,3,4,5,6,7,8,9])) 

それははるかに長く、以前のソリューションよりも明らかだが、それは私に多くのハスケルっぽいを感じています。

+1

ようこそStackOverflowへようこそ、このような良いスタートをお祝い!遠端にアクセスするためにリストを逆転させることは実際には非常に効率的です(しかし、それはむしろ非効率ですが、 'last'を使うことは、何度もやり直す必要がある場合にはさらに悪化する可能性があります。最後の要素なら、リストは適切な型ではありません)。おかげさまで – leftaroundabout

+0

ありがとうございます。私のルーキーレベルでは、実際にパフォーマンスの影響を調べるよりも、ハスケルプログラミングのイディオムを発見することにもっと興味があります。私は逆の順序で単純リンクリストを使用しようとすると間違いなく悪いケースであると私は同意します、そして、これは実際にハスケルが最初にテールパターンマッチングを提供しない理由だと思います。 (ハスケルリストは、単純リンクリストを使って実装されています。) – OlivierD

+1

正しい。 Haskellのリストはスタックとして、または無限ストリームとして素晴らしいですが、ランダムアクセスでは本当に悪いですし、遠端にアクセスすることは途中の任意の要素にアクセスすることより優れていません。 – leftaroundabout

関連する問題