1

私はジッパーをいじっています。現在の要素は、左右のリストとは異なるタイプを持つことができます。

data Z a b = Z ([a], b, [a])

moveLeftとでジッパーをナビゲートできますmoveRight

moveLeft  :: (b -> a -> a) -> (a -> b -> b) -> Z a b -> Z a b
moveLeft listF currentF (Z (x:xs, c, ys)) = Z (xs, g x c, ((f c x):ys))

moveRight :: (b -> a -> a) -> (a -> b -> b) -> Z a b -> Z a b
moveRight listF currentF (Z (xs, c, y:ys)) = Z (((f c y):xs), g y c, ys)

ここでlistFは、リスト要素と現在の要素を左また​​は右のリスト要素に変換します。currentF現在の要素とリスト要素を現在の要素に変換します。

現在のタイプとリストタイプの両方が等しい場合、移動は簡単です。

moveLeftSameType :: Z a a -> Z a a
moveLeftSameType = moveLeft const const

そして、すべてが期待どおりに機能します。

私が今やりたいのは、上記のアイデアを一般化して、与えられた(たとえば、)の関数listFと関数を実装するだけで、正しいことを自動的に実行することです。これを行う正しい方法は何でしょうか?currentFZ a ba :: Charb :: IntmoveLeftmoveRight

述べる

私はこのようなクラスを実装しようとしました:

class CPos a where
    listF :: c -> d -> d
    currentF :: d -> c -> c
    moveLeft :: a -> a
    moveRight :: a -> a

moveLeft/Rightの観点から実装されてlistFcurrentFますが、これは失敗します

The class method `listF' mentions none of the type variables of the class CPos a

備考2

上記の考え方について私が一般的に気に入らないのは、任意の機能listFを許可しているという事実でありcurrentF、保証することは不可能です

moveLeft . moveRight = id

(ジッパーがリスト内にある場合、境界線ではこれはとにかく保持されません)。これを実施するためのヒントはありますか?

4

1 に答える 1

1

これがその解決策です。

class CPos a b where
    listF :: b -> a -> a
    currentF :: a -> b -> b
    moveLeft :: Z a b -> Z a b
    moveLeft (Z (x:xs, c, ys)) = Z (xs, currentF x c, ((listF c x):ys))
    moveRight :: Z a b -> Z a b
    moveRight (Z (xs, c, y:ys)) = Z (((listF c y):xs), currentF y c, ys)

私はあなたが強制することができるとは思わないmoveLeft . moveRight = id。つまり、2つの関数が等しいことを保証することは決定不可能です。あなたができる最善のことはquickcheck、同じことを保証するためにテストケースを書くことです。

于 2012-09-14T16:28:40.793 に答える