1

Hello i want to know if it is possible to provide a parameter to a method at a specific position for further using point-free-notation:

 readData::Text->[Int]
    readData =catMaybes . maybeValues where
        maybeValues=mvalues.split.filterText

 filterText::Text->[Char]->Text
    filterText tx chars=Data.Text.filter (\x -> not (x `elem` chars)) tx

How can i provide to filterText only the 2-nd parameter? like this:

filterText "astr" where astr is the [Char] argument (second position).
Generally speaking when having a method mymethod par1 par2 par3 can i use it :
mymethod par2 and somehow to bind the second argument not the first.

Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152
  • You can use `flip` for this: https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#v:flip – Willem Van Onsem Oct 18 '18 at 09:47
  • Define `filterText :: [Char] -> Text -> Text`, problem solved. For the same reason, `filter` takes the predicate, not the list to be filtered, as its first argument. The filter condition is more intimately tied to the filter process than the thing being filtered, so it is *the* argument to the function. – chepner Oct 18 '18 at 12:39
  • Put another way, the condition defines the filter: given the `[Char]`, you get back a function of type `Text -> Text` that filters its input. – chepner Oct 18 '18 at 12:41

3 Answers3

2

pointfree.io will help with all of this, for example, when asked for

\x -> method x par2

it yields

flip method par2

and for

\x y z -> f x y z value

it yields

flip flip value . (flip .) . f

readability is something different though in my opinion.

typetetris
  • 4,586
  • 16
  • 31
2

I would avoid flip as a general rule, however providing only the second argument can for a named function be done easily by treating it as an infix operator and sectioning that:

    (`filterText` "astr")

Likewise the lambda in that function can be reduced to

      (not . (`elem` chars))

(or further to (`notElem` chars)).

But often when you find yourself in such a situation, it's worth thinking whether the function should better be defined with flipped parameters in the first place.

filterText :: [Char] -> Text -> Text
filterText chars = Data.Text.filter (`notElem` chars)

Notice that I could η-reduce away the tx parameter for free, and now you can just write filterText "astr".

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
1

You can use flip :: (a -> b -> c) -> b -> a -> c for this: with flip you take a function, and thus "flip" the parameters. You can then partially apply one parameter: the second one.

So in this specific case you can use:

foo :: Text -> Text
foo = flip filterText "astr"

You can improve the filterText as well:

filterText::Text -> [Char] -> Text
filterText tx chars = Data.Text.filter (`notElem` chars) tx

or even:

filterText::Text -> [Char] -> Text
filterText = flip (Data.Text.filter . flip notElem)
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Thank you for your answer ,indeed it solves my current problem but , i was asking in more broader terms.In the current case the parameter that i want to partial apply is the second one..but give `1...N` parameters and you want to partial apply `P` parameters anywhere in the argument positions of `1 to N` can you do that? – Bercovici Adrian Oct 18 '18 at 11:24
  • @BercoviciAdrian: you write a lambda-expression, like `\foo bar -> someFunc foo bar "data"`. – Willem Van Onsem Oct 18 '18 at 11:24