Home > OS >  Simple task on Haskell, but do not know how this code works
Simple task on Haskell, but do not know how this code works

Time:11-27

I started to study Haskell. I found a code that, every few characters (which we set with a parameter), inserts a given character (also a parameter). But I can't figure out how it works.

func1 :: [a] -> Int
func1 [] = 0
func1 (_:xs) = 1   func1 xs

func2 :: Int -> [a] -> [a]
func2 _ [] = []
func2 n xs@(_:xs')
   | n > 0     = func2 (n-1) xs'
   | otherwise = xs

func3 :: [a] -> Int -> a -> [a]

func3 xs 0 y  = xs
func3 [] n y = []
func3 xs n y
 | func1 xs < n = xs
 | otherwise = n `take` xs    [y]    func3 (drop n xs) n y

main :: IO ()
main =  do
print(func3 "1234567" 2 '@')

I understand what, for example, this func1 :: [a] -> Int does, but what does this part of the code, I do not?

func2 n xs@(_:xs')
  | n > 0     = func2 (n-1) xs'
  | otherwise = xs

Or this one?

  func3 xs 0 y  = xs
  func3 [] n y = []
  func3 xs n y
   | func1 xs < n = xs
   | otherwise = n `take` xs    [y]    func3 (drop n xs) n y

Could you explain this to me? Thanks

CodePudding user response:

I will try to go through the functions one by one.

func1 xs calculates the length of xs. [] has length 0, and the length of x : xs is one more than the length of xs.

func2 n xs@(_:xs') is not called by any other function, but I will try to explain what it would do if it were called. The pattern xs@(_:xs') might seem unusual, so lets break it down. xs@pat binds the variable xs to the pattern pat. In this case, the pattern is _:xs. The underscore matches any value and discards it. xs' matches any list. If you called func2 3 [1, 2], then this pattern would be matched. Inside the scope of the function, xs would be equal to [1, 2] and xs' would be equal to [2]. If n > 0, then func2 calls itself, where xs has been replaced by the tail of xs, and n has been replaced by n - 1. This continues until n = 0, at which point xs is just kept. Therefore, func2 n xs does essentially the same thing as drop n xs. At least as long as length xs >= n.

As you said, func3 inserts y at every nth position of xs. There are several cases: n = 0 is an edge case with no obvious behaviour, so func3 does nothing. If xs = [], there is no nth position in xs so func3 again does nothing. The last pattern distinguishes two cases using guards. This is necessary because there are no patterns for "a list of length at least n", unless n is some constant known at compile-time. In the first case, the length of xs (calculated using func1) is less than n. Again, nothing to insert since there is no position n. The second guard is where the magic happens. otherwise is literally just True and therefore this is a 'catch-all' guard. The result may be described by the following procedure: First we take the first n elements of xs. Then we append ( ) the one-element list [y]. Then we append the result of func2 applied to the remaining list.

This is the first time I posted an answer on SO, so feel free to ask if something was unclear!

  • Related