3

オブジェクトのリストがあるコードに共通のパターンがあり、それらを関数に渡してchooseユーザーに選択させます。

choose :: [a] -> (a -> String) -> IO Int

ただし、選択した要素にアクセスするにはパーシャルを使用する必要があるため、 を返すのIntは残念です。(!!)これを避けるために、私は

choose :: [a] -> [Lens' [a] a] -> (a -> String) -> IO (Lens' [a] a)

ここで、リストの各要素にアクセスするためのレンズのリストを渡します。そうすれば、実際に存在するかどうかを気にせずに、レンズの反対側にあるオブジェクトを変更しても安全だと確信できます。

このようなレンズのリストを作成するにはどうすればよいですか? 効果的に、私は必要です

makeAccessors :: [a] -> [Lens' [a] a]

おまけとして、より一般的なもの

makeAccessors' :: a -> Traversal' a b -> [Lens' a b]

トラバーサルがアクセスする各ポイントのレンズを作成することも素晴らしいでしょう

4

1 に答える 1

1

たぶん、レンズの代わりにジッパー

data ListZipper a = LZ { left :: [a], focus :: a, right :: [a] }

listToListZipper :: [a] -> Maybe (ListZipper a)
listToListZipper (a:as) = Just $ LZ [] a as
listToListZipper []     = Nothing

modifyFocus :: (a -> a) -> ListZipper a -> ListZipper a
modifyFocus f z = z { focus = f $ focus z }

goRight :: ListZipper a -> Maybe (ListZipper a)
goRight (LZ ls l (a:rs)) = Just $ LZ (l:ls) a rs
goRight _                = Nothing

goLeft :: ListZipper a -> Maybe (ListZipper a)
goLeft (LZ (a:ls) r rs) = Just $ LZ ls a (r:rs)
goLeft _                = Nothing

listZipperToList :: ListZipper a -> [a]
listZipperToList (LZ ls a rs) = reverse ls ++ a:rs

目的の要素に ( を使用してmodifyFocus)アクセスするのは簡単です。choose

choose :: [a] -> (a -> String) -> MaybeT IO (ListZipper a)
choose as f = do 
    i <- lift $  choose' as f
    let z = listToListZipper as
    MaybeT . return $ goto i z
  where choose' :: [a] -> (a -> String) -> IO Int
        choose' = ...
        goto :: Int -> ListZipper a -> Maybe (ListZipper a)
        goto 0 z = return z
        goto n z = do
          z' <- goRight z
          goto (n-1) z'

あるいは

forceValidChoice :: [a] -> (a -> String) -> IO (ListZipper a)
forceValidChoice as f = do
  mz <- runMaybeT $ choose as f
  maybe (forceValidChoice as f) return mz
于 2013-07-15T03:32:12.643 に答える