One interesting sample

I solve 99 Haskell Probems. I successfully solved the problem number 21, and when I opened the page, the following solution was proposed:

Paste the item at the specified position in the list.

insertAt :: a -> [a] -> Int -> [a] insertAt x xs (n+1) = let (ys,zs) = split xs n in ys++x:zs 

I found the (n + 1) template interesting because it looks like an elegant way of converting an insertAt argument based on 1 to a split argument based on 0 (it works from the previous exercises, essentially the same as splitAt ). The problem is that the GHC did not find this model elegant, in fact it says:

Analysis error in template: n + 1

I don’t think that the guy who wrote the answer was dumb, and I would like to know if this type of template is legal in Haskell, and if so, how to fix this solution.

+6
source share
3 answers

I believe that it was removed from the language , and this was probably when the author of 99 Haskell Problems wrote this solution, but it is no longer in Haskell.

+12
source

The problem with n+k templates goes back to the design solution in Haskell to distinguish between constructors and variables in templates by the first character of their names. If you go back to ML, a general function definition might look (using Haskell syntax)

 map f nil = nil map f (x:xn) = fx : map f xn 

As you can see, syntactically there is no difference between f and nil on the LHS of the first line, but they have different roles; f is a variable that must be bound to the first argument of map , and nil is a constructor that must be mapped to the second. Now ML makes this distinction by looking at each variable in the surrounding space and assuming the names are variables when the search is not performed. Thus, nil recognized as a constructor when the search fails. But think about what happens when there is a typo in the template:

 map f niil = nil 

(two i in niil ). niil not a constructor name in scope, so it is treated as a variable, and the definition is not interpreted correctly.

Haskell's solution to this problem is to require that constructor names begin with uppercase letters, and variable names begin with lowercase letters. And for infix operators / constructors, constructor names must begin with : while operator names cannot begin with : It also helps to distinguish between deconstructing bindings:

 x:xn = ... 

is explicitly deconstructive binding because you cannot define a function named : and

 n - m = ... 

obviously, it is a function definition, because - cannot be the name of a constructor.

But using n+k patterns such as n+1 means that + is the actual name of the function and what works as a constructor in templates. Now

 n + 1 = ... 

again ambiguous; it can be part of a function definition called (+) , or it can be a deconstructing n pattern matching. In Haskell 98, this ambiguity was resolved by declaring

 n + 1 = ... 

function definition and

 (n + 1) = ... 

deconstruction of binding. But this, obviously, was never a satisfactory solution.

+6
source

Note that now you can use presentation templates instead of n + 1 .

For instance:

 {-# LANGUAGE ViewPatterns #-} module Temp where import Data.List (splitAt) split :: [a] -> Int -> ([a], [a]) split = flip splitAt insertAt :: a -> [a] -> Int -> [a] insertAt x xs (subtract 1 -> n) = let (ys,zs) = split xs n in ys++x:zs 
+1
source

Source: https://habr.com/ru/post/975133/


All Articles