2

I saw a snippet of Haskell code that recursively joins two list together, while sorting it in an ascending order:

merge :: Ord a => [a] -> [a] -> [a]
merge [] xs = xs
merge ys[] = ys

merge first @ (x:xs) second @(y:ys)
   | x <y = x :merge xs (y:ys)
   | otherwise = y : merge ys (x:xs)

I do not understand what this line merge first @ (x:xs) second @(y:ys) does.

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Oto-Obong Eshiett
  • 527
  • 1
  • 8
  • 17
  • 3
    If you're wondering about the use of `@`, see [*What does the “@” symbol mean in reference to lists in Haskell?*](https://stackoverflow.com/q/1153465/2751851) – duplode Mar 27 '20 at 00:11
  • 7
    The spacing in your snippet is super unidiomatic and misleading. – Joseph Sible-Reinstate Monica Mar 27 '20 at 00:12
  • @duplode dont still understand, can you break it down? – Oto-Obong Eshiett Mar 27 '20 at 00:21
  • 6
    You would normally write the left hand side as `merge first@(x:xs) second@(y:ys)` as this is more readable. It is similar to `merge (x:xs) (y:ys)` , except this allows you, in the right hand side, to use `first` as a shortcut for x:xs, and `second` as a shortcut for y:ys. – jpmarinier Mar 27 '20 at 00:42
  • 1
    Does this answer your question? [What does the "@" symbol mean in reference to lists in Haskell?](https://stackoverflow.com/questions/1153465/what-does-the-symbol-mean-in-reference-to-lists-in-haskell) – MikaelF Mar 27 '20 at 00:47
  • @MikaelF it is a bit confusing as I am a beginner – Oto-Obong Eshiett Mar 27 '20 at 00:52
  • @jpmarinier i think I understand now, my main issue now is what is `(x:xs) (y:ys)`, I know `:` put adds a number to the start of the list, does the same apply to `(x:xs) and (y:ys)` – Oto-Obong Eshiett Mar 27 '20 at 01:01
  • 3
    Since `first` and `second` are not used in the body of the function, you can get rid of `first@` and `second@` altogether – luqui Mar 27 '20 at 03:06
  • @Oto-ObongEshiett `(x:xs)` uses the `:` constructor to pattern-match on the list. The first element of the list gets assigned to `x`, while the remainder of the list is assigned to `xs`. As you have already mentioned, you can also use the `:` constructor to put `x` and `xs` back together to get the list `(x:xs)`; pattern-matching is just the reverse process. – bradrn Mar 27 '20 at 05:19
  • @Oto-Obong Eshiett - Well, yes, exactly. And when a function takes a list argument, you have to allow for two patterns. The argument list can be either empty, that's the `[ ]` pattern. Or, it can be non-empty, and that's the `x : xs` pattern. Naïve definition of function length: `length [ ] = 0` and on another line: `length (x : xs) = 1 + (length xs)` – jpmarinier Mar 27 '20 at 10:19

1 Answers1

4

Simple way to find out is to try it in GHCi (the GHC interpreter). If you run:

$ ghci
Prelude> functionName bind@(first:rest) = print(bind ++ ", " ++ [first] ++ ", " ++ rest)
Prelude> functionName "test"
"test, t, est"

We see that if we invoke functionName, what we get is:

bind  => test
first => t
rest  => est

So we can say:

  1. bind takes the whole argument sent,
  2. first takes head of the argument; first element of the argument,
  3. rest takes everything except first element of the argument.
Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
akegalj
  • 379
  • 2
  • 10