2017-08-23 6 views
1

ハスケルのリストの最後の2つの要素を交換する必要がありますハスケルの最後の2つの要素を交換するには?

これは私がこれまでに持っていてコンパイルしていないものです。

swapLastTwo :: [a] -> Maybe [a] 
swapLastTwo list = case list of 
    xs:x:y -> Just (xs:y:x) 
    _ -> Nothing 

しかしこの1つはコンパイル:

swapFirstTwo :: [a] -> Maybe [a] 
swapFirstTwo list = case list of 
    x:y:xs -> Just (y:x:xs) 
    _  -> Nothing 

違いは何ですか?私はこれらのx y xsなどに問題があると思います。私はそれらとはかなり確信していません。

コンパイラは、このエラーに

• Couldn't match expected type ‘[[a]]’ with actual type ‘a’ 
     ‘a’ is a rigid type variable bound by 
     the type signature for: 
      swapLastTwo :: forall a. [a] -> Maybe [a] 
     at BuiltInList.hs:69:16 
    • In the second argument of ‘(:)’, namely ‘x’ 
     In the second argument of ‘(:)’, namely ‘y : x’ 
     In the first argument of ‘Just’, namely ‘(xs : y : x)’ 
    • Relevant bindings include 
     y :: [a] (bound at BuiltInList.hs:71:10) 
     x :: a (bound at BuiltInList.hs:71:8) 
     xs :: a (bound at BuiltInList.hs:71:5) 
     list :: [a] (bound at BuiltInList.hs:70:13) 
     swapLastTwo :: [a] -> Maybe [a] (bound at BuiltInList.hs:70:1) Failed, modules loaded: none. 

を与えていただきありがとうございます。

答えて

1

cons演算子:を使用する場合、コロンの右側の最後の項目はリストで、左側のすべてがリスト内の単一の項目です。そのため、swapFirstTwoが正常にコンパイルされるのは、xyからx:y:xsまでです。xsはリストです。

次のいずれかの方法により、2つの要素リストにパターンマッチを閉じ込めることができます。

x:y:[] -> ... 
-- or 
[x,y] -> ... 
+0

ありがとうございました。 –

+0

私はこれを持っています。おそらく私はまだ何かを理解していないでしょう... –

+0

空の配列括弧 '[]'は、私が示した例のように、_right_に行きます([]]:x:y - > Just([]:y:x) 。 –

8

まず、パターンマッチングのこの種のcaseを使用する理由がないことに注意してください - ちょうど右で一致関数の引数:

今、ハスケルリストは対称ではありません。まったく。あなたがパターンマッチングで行うことは、いつもの左にあるの最後に集中します。そのためあなたのswapLastTwoは機能しません。あなたはの右の終わりにしかリスト全体を逆アセンブルすることによって終わることができません(つまり、これは有限ののリストのためだけです)。これは、の再帰によって実行できます。まず基本例を書き出し:任意のリストよりも長いについては

swapLastTwo [] = Nothing 
swapLastTwo [_] = Nothing 
swapLastTwo [x,y] = Just [y,x] 

を、あなたは最初の要素をオフにポップして、後でそれを戻す必要があります。この場合には、それは単に再帰呼び出しが生じることがどんなJust結果にxを付加:したがって、再帰句

swapLastTwo (x:xs) = (x:) <$> swapLastTwo xs 

場合、あなたは<$>が何であるかを迷っています。

代替、ブルートフォースソリューションの種類が

swapLastTwo = fmap reverse . swapFirstTwo . reverse 

だろうこれは、実際にこの例でははるかに悪いランタイム特性を持っていますが、一般的に参照ルークさんのコメント、「単純な関数を構成する代わりに、このような手作業による再帰を行う "というソリューションはしばしばより効果的です。

+0

ありがとう!それは今働く。それがとても混乱するとは思わなかった。 –

+2

@leftroundabout、 "これは実際には非常に悪いランタイム特性を持っています":私にとってO(n)と背骨の両方が厳しいようです。あなたは 'たぶん'を取り除いてしまえば、それは怠け者/生産的になる可能性があります。 (それは 'たぶん'でも可能ですが、もう少し微妙で純粋な実装ではそれをカットしません) – luqui

+0

@luqui true、私は 'たぶん'厳密さを考えませんでした。 – leftaroundabout

0

@leftaroundaboutソリューションよりも効率的ですが、多種多様な場合は、リストをアプリケーションファンクタとして使用することはできません。

swapLastTwo :: [a] -> Maybe [a] 
swapLastTwo [] = Nothing 
swapLastTwo [_] = Nothing 
swapLastTwo xs = Just (concat $ [reverse . drop 2 . reverse, take 2 . reverse] <*> [xs]) 

*Main> swapLastTwo [] 
Nothing 
*Main> swapLastTwo [1] 
Nothing 
*Main> swapLastTwo [1,2,3,4,5] 
Just [1,2,3,5,4] 
3

ここで私が楽しいために述べた生産的なバージョンです。

ghci> swapLastTwo [1,2,3,4,5] 
[1,2,3,5,4] 
>>> swapLastTwo (1:2:3:4:5:undefined) 
[1,2,3*** Exception: Prelude.undefined 

そして、あなたはまた、私はこの答えを書いた理由は、私はasJustパターンを楽しむため、である(Maybeでそれを行う、それは厳しいものが生産性を向上させることができる方法ができます。

swapLastTwo :: [a] -> [a] 
swapLastTwo [] = [] 
swapLastTwo [x] = [x] 
swapLastTwo [x,y] = [y,x] 
swapLastTwo (x:xs) = x : swapLastTwo xs 

それは怠け者です—が適切に配置された場合、本質的に、タイプだけでは明らかでないいくつかの余分な構造情報をコード化している)。また、怠惰な依存型指定された世界では

ghci> swapLastTwo' (1:2:3:4:5:undefined) 
Just [1,2,3*** Exception: Prelude.undefined 
ghci> swapLastTwo [1] 
Nothing 

怠け者である

swapLastTwo' :: [a] -> Maybe [a] 
swapLastTwo' [] = Nothing 
swapLastTwo' [x] = Nothing 
swapLastTwo' [x,y] = Just [y,x] 
swapLastTwo' (x:xs) = (x:) <$> asJust (swapLastTwo' xs) 
    where 
    assertJust ~(Just x) = Just x 

swapLastTwo'(適切に正確なタイプで)、余分な努力なしswapLastTwoがここにある道怠け者だろうか?

関連する問題