11

Is there any way that input values to a function can be pre-defined so that a user doesn't have to define them each time?

For example, assuming I had a function "zr" which returned a list zeros of size n, such that:

zr 1 = [0] zr 5 = [0, 0, 0, 0, 0] 

And so on.

My current way of implementing it is:

zr :: [Int] -> Int -> [Int] zr x y | length x == y = x | otherwise = zr x++[y] 

But this isn't particularly elegant as every time I call zr I need to include an empty list as a parameter:

zr [] 5 

Any ideas?

Thanks!

4
  • 1
    This is a good way of implementing the requirement. If you want a nicer API, keep the implementation and write an additional wrapper function that supplies the extra argument. Don't compromise your business code for the sake of the API. Commented May 6, 2014 at 8:22
  • 1
    @KilianFoth It doesn't implement the requirement. It puts copies of y in the result and y is not expected to always equal 0. Actually it doesn't even compile. Changing the recursive case to zr (x ++ [0]) y makes it work, but it's still inelegant and inefficient (appending at the end -- although prepending would work just as well -- and recomputing length at every step) and we have replicate for this. Commented May 6, 2014 at 9:08
  • Haskell list comprehensions often simplify things and can be brief. zr = \n -> [ (0) | i <- [ 1..n ] ] >>>>>>>>>>>>>>>>> zr 1 = [0] >>>>>>>>>>>>>> zr 5 = [0.0.0.0.0] Commented Feb 21, 2018 at 22:26
  • Point free (no variable parameters) would be >>>>>>>>>>>>>>>>>>> zr = flip take $ repeat 0 >>>>>>>>> zr 5 produces the same result Commented Feb 22, 2018 at 16:10

3 Answers 3

15

I think what you're looking for is partial application:

zr' :: Int -> [Int] zr' = zr [] 

If zr is a function that takes a list and an integer, then zr [] is a function that takes only an integer n and returns zr [] n.

In your case, zr' is obviously a "temporary" function (you don't want anyone accidentally calling zr' [1] 4), so you might as well define it locally:

zr :: Int -> [Int] zr = zr' [] where zr' :: [Int] -> Int -> [Int] zr' x y | length x == y = x | otherwise = zr' x++[0] y 
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks, had thought of this, but was wondering if there was any way I could avoid having to write a second function.
I don't think it is possible - you'll have to introduce a second binding somewhere, since zr and your desired function are two different functions.
@Dario - you're welcome! This sort of pattern is usually used in FP textbooks when dealing with recursion. I'd like to add that if your function is a "classic" recursion function - you can probably implement it using a higher-order function (fold,map,filter). Try is as an exercise!
Also note that zr = flip replicate 0
I think it should be noted that forward-recursion like in this answer and OP isn't feasible for the task, as I showed in my post below; forward-recursion is in most cases much longer and harder to read and run than backwards-recursion. (See stackoverflow.com/questions/3042954/…)
|
7

Not a Haskell pro myself, but I don't know a way besides defining a shorthand function (zz n = zr [] n).

In your concrete case there however is another solution:
You shouldn't loop the output through parameters, use the return value as means of recursion:

zr 0 = [] zr n = 0:(zr (n-1)) 

This will result in 0:0:[] for zr 2, which evaluates to [0,0].

Your version is very ineffective because it counts the length of the list on every step, keeps the end value around for no reason (you can decrement it and have 0 as end point) and also have a comparison.

Comments

1

Depending on what you want there are three options:

  1. Passing a record type with function arguments, and defining "defaultParameters" with default values for these arguments (see example in System.Process module)
  2. If you want to allow for just a single optional function parameter, you might consider using Maybe datatype, and pass Nothing if default is good enough.
  3. If you want to have a local defaults that depend on scope, then use GHC extension ImplicitParams. It will let you define defaults for a given code section, that are then used by everything in scope of this section.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.