[Haskell-cafe] Functions that return functions
Lennart Augustsson
lennart at augustsson.net
Sun Apr 12 18:59:24 EDT 2009
You should use an curried function as f instead of a uncurried one.
Uncurried functions are rarely used in Haskell.
-- Lennart
On Sun, Apr 12, 2009 at 10:09 PM, michael rice <nowgate at yahoo.com> wrote:
> Thanks, guys!
>
> Boy, this bunch of complemented partially applied functions gives a whole
> new meaning to the term "thinking ahead." And the whole shebang is waiting
> on that input integer to set everything in motion. Pretty clever.
>
>
> To generalize, I changed the function to:
>
> makeVerifier :: ((Int,Int) -> Int) -> Int -> (Int -> Bool)
> makeVerifier f m = divides m . foldl (+) 0 . map f . zip [1 .. ] . digits
>
> so, in Haskell
>
> let checkIsbn = makeVerifier (\ (i,d) -> i * d) 11
>
> let checkUpc = makeVerifier (\ (i,d) -> if odd i then d else 3*d) 10
>
> let checkCc = makeVerifier (\ (i,d) -> if odd i then d else if d < 5 then
> 2*d else 2*d+1) 10
>
> let checkUsps = makeVerifier (\ (i,d) -> if i == 1 then -d else d) 9
>
>
> I think I'm catching on.
>
> Michael
>
>
>
> --- On Sun, 4/12/09, Daniel Fischer <daniel.is.fischer at web.de> wrote:
>
> From: Daniel Fischer <daniel.is.fischer at web.de>
> Subject: Re: [Haskell-cafe] Functions that return functions
> To: haskell-cafe at haskell.org
> Cc: "michael rice" <nowgate at yahoo.com>
> Date: Sunday, April 12, 2009, 12:15 PM
>
> Am Sonntag 12 April 2009 17:38:53 schrieb michael rice:
>> The following are exercises 5.10, and 5.11 from the Scheme text "Concrete
>> Abstractions" by Max Hailperin, et al. The text at that point is about
>> writing verifiers to check ID numbers such as ISBNs, credit card numbers,
>> UPCs, etc.
>>
>> ======
>>
>> Exercise 5.10
>> Write a predicate that takes a number and determines whether the sum of
>> its
>> digits is divisible by 17.
>>
>> Exercise 5.11
>> Write a procedure make-verifier, which takes f and m as its two arguments
>> and returns a procedure capable of checking a number. The argument f is
>> itself a procedure of course. Here is a particularly simple example of a
>> verifier being made and used.
>>
>> (define check-isbn (make-verifier * 11))
>>
>> (check-isbn 0262010771)
>> #t
>>
>> The value #t is the "true" value; it indicates that the number is a valid
>> ISBN.
>>
>> As we just saw, for ISBN numbers the divisor is 11 and the function is
>> simply f(i,d(i)) = i * d(i). Other kinds of numbers use slightly more
>> complicated functions, but you will still be able to use make-verifier to
>> make a verifier much more easily than if you had to start from scratch.
>>
>> =======
>>
>> Here's the Scheme check-verifier function I wrote, followed by my humble
>> attempt at a Haskell function that does the same thing. Below that are
>> some
>> verifier functions created with the Scheme make-verifier. Admittedly,
>> functions that return functions are Lispy, but perhaps there a Haskelly
>> way
>> to accomplish the same thing?
>
> Functions returning functions are quite natural in Haskell.
> Since usually functions are written in curried form, a function returng a
> function
> corresponds to a function of multiple arguments applied to only some of
> them.
>
>>
>> Michael
>>
>> ===============
>>
>>
>> (define (make-verifier f m) ;f is f(i,d) & m is divisor
>> (lambda (n)
>> (let* ((d (digits n))
>> (i (index (length d)))) ;(index 3) => (1 2 3)
>> (divides? m (reduce + 0 (map f i d)))))) #f
>>
>> makeVerifier :: (Int -> Int -> Int) -> Int -> (Int -> Bool)
>>
>> makeVerifier f m = \n -> let d = digits n
>>
>> i = [1..(length d)]
>>
>> in \n -> divides m (foldl (+) 0 (map2 f i d))
>>
>>
>
> makeVerifier f m n = divides m . foldl (+) 0 $ zipWith f [1 .. ] (digits n)
>
> just call makeVerifier f m to get your verification function :)
>
> If you don't want to name the last argument:
>
> makeVerifier f m = divides m . foldl (+) 0 . zipWith f [1 .. ] . digits
>
> more point-freeing would be obfuscation.
> Instead of foldl (+) 0, you could also just write sum.
>
>>
>> -- Note: Reduce is just foldl f 0 lst, but map2 is
>> map2 :: (Int -> Int -> Int) -> [Int] -> [Int] -> [Int]
>> map2 f m n = [ f i d | (i,d) <- zip m n]
>
> map2 is zipWith, already in the Prelude.
>
>>
>> -- And here's my digits function
>> digits :: Int -> [Int]
>> digits 0 = []
>> digits n = rem n 10 : digits (quot n 10)
>
> Unless you are desperate for speed and sure you deal only with positive
> numbers (or know
> that you really want quot and rem), better use div and mod. Those give the
> commonly
> expected (unless your expectation has been ruined by the behaviour of % in
> C, Java...)
> results.
>
>>
>> -- And divides function
>> divides :: Int -> Int -> Bool
>> divides divisor n = 0 == rem n divisor
>>
>> =====
>>
>> (define check-isbn ;book number
>> (make-verifier
>> *
>> 11))
>>
>> (define check-upc ;universal product code
>> (make-verifier
>> (lambda (i d) (if (odd? i) d (* 3 d)))
>> 10))
>>
>> (define check-cc ;credit card
>> (make-verifier
>> (lambda (i d) (if (odd? i) d (if (< d 5) (* 2 d) (+ (* 2 d) 1))))
>> 10))
>>
>> (define check-usps ;postal money order
>> (make-verifier
>> (lambda (i d) (if (= i 1) (- d) d))
>> 9))
>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>
More information about the Haskell-Cafe
mailing list