Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

Haskell/Solutions/Lenses and functional references

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

The scenic route to lenses Traversals 1. extremityCoordinates :: Applicative f => (Double -> f Double) -> Segment -> f Segment extremityCoordinates g (Segment start end) = Segment <$> pointCoordinates g start <*> pointCoordinates g end Setters 1. scaleSegment :: Double -> Segment -> Segment scaleSegment x = over extremityCoordinates (x *) 2. mapped :: Functor f => (a -> Identity b) -> f a -> Identity (f b) mapped f = Identity . fmap (runIdentity . f) Lenses at last 1. positionX :: Functor f => (Double -> f Double) -> Point -> f Point positionX k p = (\x -> p { _positionX = x }) <$> k (_positionX p) positionY :: Functor f => (Double -> f Double) -> Point -> f Point positionY k p = (\y -> p { _positionY = y }) <$> k (_positionY p) segmentStart :: Functor f => (Point -> f Point) -> Segment -> f Segment segmentStart k s = (\p -> s { _segmentStart = p }) <$> k (_segmentStart s) segmentEnd :: Functor f => (Point -> f Point) -> Segment -> f Segment segmentEnd k s = (\p -> s { _segmentEnd = p }) <$> k (_segmentEnd s) 2. lens :: Functor f => (s -> a) -> (s -> b -> t) -> (a -> f b) -> s -> f t lens getter setter = \k x -> setter x <$> k (getter x) A swiss army knife Prisms 1a. The challenge lies in decoding the type of outside: outside :: Prism s t a b -> Lens (t -> r) (s -> r) (b -> r) (a -> r) It is easier to get a general idea of what is going on if we specialise it to prisms that do not change types. Prism' s a -> Lens' (s -> r) (a -> r) Given a Prism' that aims at a possible target of type a within an s, outside gives us a Lens' that aims at a a -> r function within a s -> r function. If we go back to the original type, which allows type-changing prisms, we note that the s/t and a/b pairs are swapped. That happens because the type variables of the prism appear in the arguments of the functions the lens deals with. We might say that outside is contravariant, in a similar sense to the one we used when discussing contarvariant functors earlier in the chapter. There is something very odd in what we just said that requires further explanation. What can possibly mean saying that a function is within another function? To answer that, let's have a look at the type of either: either :: (a -> c) -> (b -> c) -> Either a b -> c either f _ (Left x) = f x either _ g (Right y) = g y either extracts a value from an Either a b value. To do so, it relies on two functions: a a -> c one that handles values wrapped by Left and a b -> c one to handle Right. either f g is then a Either a b -> c that can be seen as being made of two components, f and g, each of them handling one of Either's constructors. These function components are what outside modifies. It is in that sense that outside uses a prism as a "first-class pattern". Any Either a b -> c function is necessarily doing pattern matching, deconstructing an Either a b to produce its c result. outside _Left and outside _Right allow us to modify the way such a function handles each pattern. 1b. maybe :: b -> (a -> b) -> Maybe a -> b maybe xNothing fJust = outside _Just .~ fJust $ const xNothing -- A default Maybe a -> b function. either :: (a -> c) -> (b -> c) -> Either a b -> c either fLeft fRight = outside _Left .~ fLeft $ outside _Right .~ fRight $ error "Impossible" -- There is no sensible default here.