c) -> (a -...">

Functional composition Designation

Is there a "do notation" syntactic sugar for a simple composition of functions?

(i.e. (.) :: (b -> c) -> (a -> b) -> a -> c )

I would like to be able to store the results of some compositions later (while continuing the chain).

I would prefer not to use the RebindableSyntax extension if possible.

I am looking for something like this:

 composed :: [String] -> [String] composed = do fmap (++ "!!!") maxLength <- maximum . fmap length filter ((== maxLength) . length) composed ["alice", "bob", "david"] -- outputs: ["alice!!!", "david!!!"] 

I'm not sure that this is possible, since the result of an earlier function should essentially go through the maxLength binding, but I'm open to listening to any other similar expressive options. Basically, I need to collect information when I look at a composition so that I can use it later.

Perhaps I could do something similar with a state monad?

Thank you for your help!

Edit

This kind of genus works:

 split :: (a -> b) -> (b -> a -> c) -> a -> c split ab bac a = bac (ab a) a composed :: [String] -> [String] composed = do fmap (++ "!!!") split (maximum . fmap length) (\maxLength -> (filter ((== maxLength) . length))) 
+7
composition haskell do-notation
source share
4 answers

As mentioned by leftaroundabout , you can use Arrows to record your function. But there is a function in the ghc Haskell compiler that is proc -notation for Arrows. It is very similar to the well-known do -notation, but, unfortunately, few people know about it.

With proc -notation, you can write your desired function in the following more scalable and elegant way:

 {-# LANGUAGE Arrows #-} import Control.Arrow (returnA) import Data.List (maximum) composed :: [String] -> [String] composed = proc l -> do bangedL <- fmap (++"!!!") -< l maxLen <- maximum . fmap length -< bangedL returnA -< filter ((== maxLen) . length) bangedL 

And this works in ghci, as expected:

 ghci> composed ["alice", "bob", "david"] ["alice!!!","david!!!"] 

If you're interested, you can read some tutorials with good images to understand what the arrow is and how this powerful feature works so you can dive deeper into it:

https://www.haskell.org/arrows/index.html

https://en.wikibooks.org/wiki/Haskell/Understanding_arrows

+2
source share

One of the possible ways to achieve something like this is with arrows. Basically, in โ€œsaving intermediate resultsโ€ you simply share the flow of information through a chain of compositions. This is what &&& (fanout) does .

 import Control.Arrow composed = fmap (++ "!!!") >>> ((. length) . (==) . maximum . fmap length &&& id) >>> uncurry filter 

This is definitely not good human-readable code, though.

It is assumed that the state monad allows something related, but the problem is that the type of state is fixed through the monadic chain do . It is not very flexible to accept different typed meanings throughout the composition chain. Although it is certainly possible to get around this (among them, indeed, RebindableSyntax ), this is also not a good IMO idea.

+5
source share

Type (<*>) specialized for the Applicative function instance:

 (<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b) 

The resulting function r -> b passes its argument to both the functions r -> a -> b and r -> a , and then uses the value a created by the function r -> a as the second argument r -> a -> b one .

What does this have to do with your function? filter is a function of two arguments, a predicate and a list. Now the key aspect of what you are trying to do is that the predicate is generated from the list. This means that the core of your function can be expressed in terms of (<*>) :

 -- Using the predicate-generating function from leftaroundabout answer. maxLengthOnly :: Foldable t => [ta] -> [ta] maxLengthOnly = flip filter <*> ((. length) . (==) . maximum . fmap length) composed :: [String] -> [String] composed = maxLengthOnly . fmap (++ "!!!") 

This definition of maxLengthOnly would be a pretty nice one-liner if the zero-point predicate generation function was not so awkward.

Since the Applicative function instance is equivalent in power to Monad , maxLengthOnly can also be stated as:

 maxLengthOnly = (. length) . (==) . maximum . fmap length >>= filter 

( split added to your question, by the way, (>>=) for functions.)

Another way to record using Applicative :

 maxLengthOnly = filter <$> ((. length) . (==) . maximum . fmap length) <*> id 

It is no coincidence that this is very similar to the leftaroundabout solution: for functions (,) <$> f <*> g = liftA2 (,) fg = f &&& g .

Finally, it is also worth noting that, although the latest version of maxLengthOnly with fmap (++ "!!!") is tempted to replace id , this will not work because fmap (++ "!!!") changes the length of the lines, and therefore, it affects the result of the predicate. However, with a function that does not invalidate the predicate, it will work very well:

 nicerComposed = filter <$> ((. length) . (==) . maximum . fmap length) <*> fmap reverse 
 GHCi> nicerComposed ["alice","bob","david"] ["ecila","divad"] 
+3
source share

What you have is essentially a filter, but one where the filter function changes as it goes through the list. I would model it not as a โ€œbranchedโ€ composition, but as a fold using the following function f :: String -> (Int, [String]) :

  • The return value supports the current maximum and all rows of this length.
  • If the first argument is shorter than the current maximum, leave it.
  • If the first argument matches the current maximum, add it to the list.
  • If the first argument is longer, make its length a new maximum and replace the current output list with a new list.

Once the fold is complete, you simply retrieve the list from the tuple.

 -- Not really a suitable name anymore, but... composed :: [String] -> [String] composed = snd . foldr f (0, []) where f curr (maxLen, result) = let currLen = length curr in case compare currLen maxLen of LT -> (maxLen, result) -- drop EQ -> (maxLen, curr:result) -- keep GT -> (length curr, [curr]) -- reset 
+1
source share

All Articles