7

Maybeタイプ(または部分性をモデル化するための他のタイプ)内にネストされた値を変更する最もクリーンな方法を見つけようとしています。

セットアップ例は次のとおりです。

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data Outer = Outer { _inner :: Maybe Inner }
  deriving (Show)

data Inner = Inner { _foo :: Int }
  deriving (Show)

makeLenses ''Outer
makeLenses ''Inner

これをやや厄介な方法で行うのは非常に簡単ですlens

wibble :: Outer -> Maybe Outer
wibble o = do i <- view inner o
              let i' = over foo succ i
              return $ set inner (Just i') o

これが厄介な理由を指摘するために、私が書きたいことは次のとおりです。

wibble' :: Outer -> Maybe Outer
wibble' = overish inner.foo succ

overish = ???

フィールドの検索に失敗すると、発生する可能性のある各ポイントで失敗を明示的にチェックするのではなく、操作全体が失敗するだけです。

助言がありますか?さまざまなモジュールをナビゲートしてみましたlensが、法案に合うものは何もありません。

4

1 に答える 1

8

over (inner.traverse.foo)ネストされたフィールドへの書き込みに使用できます。ただし、0個のターゲットすべてのマッピングに成功したため、これは希望どおりの失敗を報告しません。

traverse(からData.Traversable、によって再エクスポートされたControl.Lens)ここでは、Traversal上を歩くためのを提供しますMaybe

(^?)レンズのターゲットが存在するかどうかを確認するためにそれから読み取ることができます。

既存のレンズコンビネータを使用して個別に読み取りと書き込みを行うことで、これをいくつかの方法で解決できますが、そのようなコンビネータを直接構築することもできます。

import Data.Monoid (Any(..))
import Control.Monad (guard)

overish :: LensLike ((,) Any) s t a b -> (a -> b) -> s -> Maybe t
overish l f s = case l (\a -> (Any True, f a)) s of
  (Any r, t) -> t <$ guard r

これもで書くことができl %%~ \a -> (Any True, f a)ます。

Traversalを使用すると、aにターゲットがないかどうかを簡単に確認できますnullOfが、これには2つのパスと上位のタイプが必要になります。

overish :: Traversal s t a b -> (a -> b) -> s -> Maybe t
overish l f s = over l f s <$ guard (not (nullOf l s))

これは事実上、ターゲットがあることを確認し、ターゲットがある場合はそれにセッターを適用するだけです。

その後、あなたはただ使うことができます

overish (inner.traverse.foo) succ
于 2012-12-07T03:21:46.030 に答える