Per il controesempio, dobbiamo prima definire un nuovo tipo di dati, per la quale generiamo attraversamenti con makePrisms
:
data T = A T | C deriving Show
makePrisms ''T
_A :: Traversal T T
è ora un attraversamento valida. Ora, costruire un nuovo attraversamento utilizzando failing
:
t :: Traversal' T T
t = failing _A id
noti che (C & t .~ A C) ^.. t = [C]
, che sembra che fallisce una legge attraversamento (non è "ottiene ciò che si mette in"). Infatti, la seconda legge attraversamento è:
fmap (t f) . t g ≡ getCompose . t (Compose . fmap f . g)
che non è soddisfatta, come si può vedere con la seguente scelta per f
e g
:
-- getConst . t f = toListOf t
f :: T -> Const [T] T
f = Const . (:[])
-- runIdentity . t g = t .~ A C
g :: T -> Identity T
g = pure . const (A C)
Poi:
> getConst . runIdentity . fmap (t f) . t g $ C
[C]
Mentre :
> getConst . runIdentity . getCompose . t (Compose . fmap f . g) $ C
[A C]
Quindi esiste effettivamente un caso in cui failing
con attraversamenti validi non produce un attraversamento valido.
Per quello che vale, non vedo come questo possa generare traversali non validi. –