Haskell newbie on understanding function composition - haskell

I've been reviewing this code fragment from the Haskell Hierarchical library.
I can follow most of the fragments of the code below, but the "." (function composition) behavior in this case has thrown me because of what I expect the arguments to be for foldr, specifically: foldr f z list. I see parseLine as f, z as M.empty, lines as list. So I expect my confusion is around the behavior of the function composition and the where clause. Any assistance in understanding this function would be much appreciated as I try and make sense out of Haskell.
-- Parse the file we've just read in, by converting it to a list of lines,
-- then folding down this list, starting with an empty map and adding the
-- username and password for each line at each stage.
parseMap :: String -> PassDB
parseMap = foldr parseLine M.empty . lines
where parseLine ln map =
let [un, pw] = words ln
in M.insert un pw map

You have to parse this expression as (foldr parseLine M.empty) . (lines). So you are right that parseLine and M.empty are the first and second argument to foldr here. However, lines is not an argument to foldr.
So foldr is still missing one argument, that is, foldr parseLine M.empty is a function of type [String] -> PassDB. And lines is also missing one argument, it is a function from String -> [String]. And that's the two functions that the . is composing here. So together we get a function of type String -> PassDB.
Note that the argument is still missing, so parseMap is a function. Just as its type annotation says.

First I should say that in Haskell, all functions take one argument. That's called currying and that is what allows the syntax you posted.
Then, this syntax is an instance of pointfree style. You can read it in a pointful style as follows:
parseMap :: String -> PassDB
parseMap s = foldr parseLine M.empty . lines $ s
where parseLine ln map =
let [un, pw] = words ln
in M.insert un pw map
Going from the above form to the form you posted is called performing an eta-reduction.
You can be warned by smart editors that integrate hlint (such as emacs with haskell-mode) when you can perform eta-reduction.
When you've understood all that, understanding the function composition is just realizing that the input string will first be given as input to lines, that function will turn the string into a list, and then the resulting list will be given to foldr.

Related

Haskell Pattern Matching (beginner)

I have to implement a small programm in Haskell that increments/decrements a result by what in the console line is. For example if we have -a in the console the results must be 0, if -b the result must be incremented with 6 and so on. I have to do this with pattern matching.
I haven't used Haskell until now and I find it pretty hard to understand. I have this to start with:
import System.Environment
main = getArgs >>= print . (foldr apply 0) . reverse
apply :: String -> Integer -> Integer
I don't understand what in the main is. What does it make and the reverse from end, what does it do? As I've read on the internet the getArgs function gives me the values from the console line. But how can I use them? Are there are equivalent functions like for/while in Haskell?
Also, if you have some examples or maybe could help me, I will be very thankful.
Thanks!
This is not beginner-friendly code. Several shortcuts are taken there to keep the code very compact (and in pointfree form). The code
main = getArgs >>= print . (foldr apply 0) . reverse
can be expanded as follows
main = do
args <- getArgs
let reversedArgs = reverse args
result = foldr apply 0 reversedArgs
print result
The result of this can be seen as follows. If the command line arguments are, say, args = ["A","B","C"], then we get reversedArgs = ["C","B","A"] and finally
result = apply "C" (apply "B" (apply "A" 0))
since foldr applies the function apply in such way.
Honestly, I'm unsure about why the code uses reverse and foldr for your task. I would have considered foldl (or, to improve performance, foldl') instead.
I expect the exercise is not to touch the given code, but to expand on it to perform your function. It defines a complicated-looking main function and declares the type of a more straight forward apply, which is called but not defined.
import System.Environment -- contains the function getArgs
-- main gets arguments, does something to them using apply, and prints
main = getArgs >>= print . (foldr apply 0) . reverse
-- apply must have this type, but what it does must be elsewhere
apply :: String -> Integer -> Integer
If we concentrate on apply, we see that it receives a string and an integer, and returns an integer. This is the function we have to write, and it can't decide control flow, so we can just get to it while hoping the argument handling works out.
If we do want to figure out what main is up to, we can make a few observations. The only integer in main is 0, so the first call must get that as its second argument; later ones will be chained with whatever is returned, as that's how foldr operates. r stands for from the right, but the arguments are reversed, so this still processes arguments from the left.
So I could go ahead and just write a few apply bindings to make the program compile:
apply "succ" n = succ n
apply "double" n = n + n
apply "div3" n = n `div` 3
This added a few usable operations. It doesn't handle all possible strings.
$ runhaskell pmb.hs succ succ double double succ div3
3
$ runhaskell pmb.hs hello?
pmb.hs: pmb.hs:(5,1)-(7,26): Non-exhaustive patterns in function apply
The exercise should be about how you handle the choice of operation based on the string argument. There are several options, including distinct patterns as above, pattern guards, case and if expressions.
It can be useful to examine the used functions to see how they might fit together. Here's a look at a few of the used functions in ghci:
Prelude> import System.Environment
Prelude System.Environment> :t getArgs
getArgs :: IO [String]
Prelude System.Environment> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Prelude System.Environment> :t print
print :: Show a => a -> IO ()
Prelude System.Environment> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
Prelude System.Environment> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Prelude System.Environment> :t reverse
reverse :: [a] -> [a]
This shows that all the strings come out of getArgs, it and print operate in the IO monad, which must be the m in >>=, and . transfers results from the right function into arguments for the left function. The type signature alone doesn't tell us what order foldr handles things, though, or what reverse does (though it can't create new values, only reorder including repetition).
As a last exercise, I'll rewrite the main function in a form that doesn't switch directions as many times:
main = print . foldl (flip apply) 0 =<< getArgs
This reads from right to left in a data flow sense and handles arguments from left to right because foldl performs left-associative folding. flip is just there to match the argument order for apply.
As suggested in the comment, hoogle is a great tool.
To find out what exactly you get from getArgs you can search for it on hoogle:
https://hackage.haskell.org/package/base-4.11.1.0/docs/System-Environment.html#v:getArgs
As you can see, it's of type IO [String].
Since I don't know how familiar you are with the IO abstractions yet, we'll just say that the right part of >>= gets those as argument.
The arguments for a call like ./a.out -a -b --asdf Hi will then be a list of strings:
["-a", "-b", "--asdf", "Hi"].
The fold + reverse in the main will then do some magic, and your apply function will be called with each string in the list and the previous return value (0 for the first invocation).
In Haskell, String is the same as [Char] with a bit of compiler sugar, so you can match on strings like you would on regular lists in your definition of apply.

Harvesting function outputs (as well as inputs) from Haskell Quickcheck

What is the best way to tuple: 1. QuickCheck inputs to a predicate with 2. the outputs returned by a tested function ?
Wanting to test (2 * 350) functions in a couple of other languages (to check for divergence from the behaviour of the Haskell base and Prelude functions which they imitate) my first experiment has been to:
capture output from (QuickCheck) verboseCheck result strings
apply the Haskell function to each of the (re-read) inputs which QuickCheck threw at it, to obtain the corresponding Haskell output
use these inputs and outputs in automated checks of the parallel functions in other languages for divergences from the behaviour of the Haskell function
For example, to get test data for a function on a list, something like:
testSet1
:: (Show a, Testable prop)
=> String -> String -> ([Int] -> a) -> prop -> IO ()
testSet1 folder fname f p = do
r <- verboseCheckResult p
let ys =
((,) <*> f) . read . listTuple1 <$>
splitOn ["Passed:"] (tail $ init $ (lines . output) r)
writeFile (concat [folder, fname, ".txt"]) (show ys)
This works OK, at least for simple cases, but I cannot immediately find ways of generalising this kind of pattern to avoid having to write a separate function (to generate and capture inputs with outputs) for every variant of type signature.
The key problem is that read typically needs some type information with which to parse the list of QuickCheck-generated inputs from their (QuickCheck result output) stringifications.
Perhaps I am taking the wrong approach. Any thoughts ? Template Haskell ?
There is a separate package to annotate properties with counterexamples (which can consist of inputs and outputs): quickcheck-with-counterexamples.
This QuickCheck issue on Github has some discussion on the same topic.

The real sense of list generators in haskell

As I understand, the code
l = [(a,b)|a<-[1,2],b<-[3,4]]
is equivalent to
l = do
a <- [1,2]
b <- [3,4]
return (a,b)
or
[1,2] >>= (\a -> [3,4] >>= (\b -> return (a,b)))
The type of such expression is [(t,t1)] where t and t1 are in Num.
If I write something like
getLine >>= (\a -> getLine >>= (\b -> return (a,b)))
the interpreter reads two lines and returns a tuple containing them.
But can I use getLine or something like that in list generators?
The expression
[x|x<-getLine]
returns an error "Couldn't match expected type [t0]' with actual typeIO String'"
But, of course, this works in do-notation or using (>>=).
What's the point of list generators, and what's the actual difference between them and do-notation?
Is there any type restriction when using list gens?
That's a sensible observation, and you're not the first one to stumble upon that. You're right that the translation of [x|x<-getLine] would lead to a perfectly valid monadic expression. The point is that list comprehensions were, I think, first only introduced as convenience syntax for lists, and (probably) no one thought that people might use them for other monads.
However, since the restriction to [] is not really a necessary one, there is a GHC extension called -XMonadComprehensions which removes the restriction and allows you to write exactly what you wanted:
Prelude> :set -XMonadComprehensions
Prelude> [x|x<-getLine]
sdf
"sdf"
My understanding is that list comprehensions can only be used to construct lists.
However, there's a language extension called "monad comprehensions" that allows you to use any arbitrary monad.
https://ghc.haskell.org/trac/ghc/wiki/MonadComprehensions

Create concatenate function in Haskell: [String] -> String

I'm having a lot of trouble getting this function to work:
concatenate :: [String] -> String
It is designed to simply take a list of strings and return a single string that is the result of the concatenations of each element of the list from head to tail. I'm trying to stay within the map, foldl, and foldr functions. I feel like I know what the concept of these functions do well enough, but the most common problem I'm running into is that I'm having a conflict of types. GHC will expect a [Char] for example, and I'll put in code that is apparently trying to use a [[Char]] without me knowing it.
For example: concatenate (x:xs) = foldr (++) x (concatenate xs)
And I get the following compile error:
Couldn't match type `Char' with `[Char]'
Expected type: [[Char]]
Actual type: String
In the return type of a call of `concatenate'
In the third argument of `foldr', namely `(concatenate xs)'
In the expression: foldr (++) x (concatenate xs)
I'm very new to Haskell, so please feel free to laugh. Harshness is expected, and welcomed, as long as an explanation fit for a newbie is also included. Thank you for any and all help.
You actually don't need the recursive call there. The function foldr already simulates a recursive call. All you need to do is use:
concatenate :: [String] -> String
concatenate ls = foldr (++) "" ls
And remember that there's a concat function already, which is more generic, as it works on any list of list (as opposed to simply list of strings).

Difference between composition and function application [duplicate]

This question already has answers here:
What is the difference between . (dot) and $ (dollar sign)?
(13 answers)
Closed 8 years ago.
The first problem in 99 Haskell Problems is to "find the last element of a list". I came up with two solutions:
Solution 1 (This works)
myLast :: [a] -> a
myLast = head . reverse
Solution 2 (This doesn't work)
myLast :: [a] -> a
myLast = head $ reverse
Question
Why does solution 1 work but not solution 2? What I'm most confused by is how neither implementations supply pattern matching.
head is a function of one argument1. If you use f $ x to apply a function to something, it's the same as simply writing f x (or if you like f(x), or (f)x, all the same thing... just uglier): the argument is "filled in" by the specified variable. So the result of head $ reverse will simply be whatever result head gives you when fed with an argument of reverse's type... ...which however doesn't work, because head needs a list but reverse is a function. $ itself doesn't care about this but just hands on the parameter, for instance you could write
Prelude> :t map $ reverse
map $ reverse :: [[a]] -> [[a]]
because the first argument of map is in fact a function.
With (.) it's different. That cares about what type the argument to its right has (must also be a function), and it doesn't simply feed it to the left function right away. Rather, f . g yields another function, which does the following: it waits for some argument x, which it feeds to g, and then feeds the result of that to f.
Now, if you write
myLast' = head . reverse
it means just, you define myLast as this function that (.) gives you as the composition of head and reverse. That there are no arguments mentioned for myLast here doesn't matter: [a] -> a is just some type so you can define variables with this type (like myLast), by assigning them to values that happen to have such a function type (like head . reverse). You could, if you wanted, make the parameter explicit:
myLast'' x = (head . reverse) x
Note that the parens are needed because otherwise it's parsed as head . (reverse x) – which wouldn't work, because reverse x is not a function anymore, just a result list. And therefore you couldn't compose it with head; what you could however do is apply head to it:
myLast''' x = head $ reverse x
1In fact, every function in Haskell has just one argument... but we say "two-argument function" for things like (+) :: Int -> Int -> Int, though really this is a one-argument function returning a one-argument function returning an Int: (+) :: Int -> (Int -> Int).
Roughly, application ($) is used between a function and its argument (a list in this case), while composition (.) is used between two functions.
About pattern matching: in the first solution, the function reverse will perform the needed pattern match for you, so myLast does not have to.

Resources