<table cellspacing="0" cellpadding="0" border="0" ><tr><td valign="top" style="font: inherit;">All I meant was a small change:<br>> makeVerifier :: (Int -> Int -> Int) -> Int -> (Int -> Bool)<br>> makeVerifier f m = divides m . foldl (+) 0 . zipWith f [1 .. ] . digits<br><br>which make some things simpler:<br><br>> let checkIsbn = makeVerifier (*) 11 <== I liked this syntax better too, and it's what I had<br> originally.<br><br><br>BTW, here's a sneaky way do define digits:<br>> digits :: Int -> [Int]<br>> digits = map digitToInt . show <== I haven't gotten to "show" yet. When needed? When not?<br><br>So then
you'd have:<br><br>> makeVerifier :: (Int -> Int -> Int) -> Int -> Int -> Bool<br>> makeVerifier f m = (== 0) . (`mod` m) . sum . zipWith f [1 .. ] . map digitToInt . show<br><br>Which looks pretty nice, I think.<br><br> -- Lennart<br><br>========<br><br>Very good. I've yet to replace the 'foldl' with 'sum', but will. Eliminating the 'divides' function is also a nice touch. With Haskell it seems there's always a way to make one's code ever briefer, and using built-ins is probably much faster than anything I'd cook up, but it takes time to learn these short-cuts.<br><br>Thanks for your comments.<br><br>Michael<br><br><br>--- On <b>Mon, 4/13/09, Lennart Augustsson <i><lennart@augustsson.net></i></b> wrote:<br><blockquote style="border-left: 2px solid rgb(16, 16, 255); margin-left: 5px; padding-left: 5px;"><br>From: Lennart Augustsson <lennart@augustsson.net><br>Subject: Re: [Haskell-cafe] Functions that return
functions<br>To: "michael rice" <nowgate@yahoo.com><br>Cc: haskell-cafe@haskell.org<br>Date: Monday, April 13, 2009, 10:33 AM<br><br><div class="plainMail">All I meant was a small change:<br>> makeVerifier :: (Int -> Int -> Int) -> Int -> (Int -> Bool)<br>> makeVerifier f m = divides m . foldl (+) 0 . zipWith f [1 .. ] . digits<br><br>which make some things simpler:<br><br>> let checkIsbn = makeVerifier (*) 11<br><br>BTW, here's a sneaky way do define digits:<br>> digits :: Int -> [Int]<br>> digits = map digitToInt . show<br><br>So then you'd have:<br><br>> makeVerifier :: (Int -> Int -> Int) -> Int -> Int -> Bool<br>> makeVerifier f m = (== 0) . (`mod` m) . sum . zipWith f [1 .. ] . map digitToInt . show<br><br>Which looks pretty nice, I think.<br><br> -- Lennart<br><br>On Mon, Apr 13, 2009 at 1:09 AM, michael rice <<a ymailto="mailto:nowgate@yahoo.com"
href="/mc/compose?to=nowgate@yahoo.com">nowgate@yahoo.com</a>> wrote:<br>> Example please.<br>><br>> Michael<br>><br>> --- On Sun, 4/12/09, Lennart Augustsson <<a ymailto="mailto:lennart@augustsson.net" href="/mc/compose?to=lennart@augustsson.net">lennart@augustsson.net</a>> wrote:<br>><br>> From: Lennart Augustsson <<a ymailto="mailto:lennart@augustsson.net" href="/mc/compose?to=lennart@augustsson.net">lennart@augustsson.net</a>><br>> Subject: Re: [Haskell-cafe] Functions that return functions<br>> To: "michael rice" <<a ymailto="mailto:nowgate@yahoo.com" href="/mc/compose?to=nowgate@yahoo.com">nowgate@yahoo.com</a>><br>> Cc: <a ymailto="mailto:haskell-cafe@haskell.org" href="/mc/compose?to=haskell-cafe@haskell.org">haskell-cafe@haskell.org</a>, "Daniel Fischer" <<a ymailto="mailto:daniel.is.fischer@web.de" href="/mc/compose?to=daniel.is.fischer@web.de">daniel.is.fischer@web.de</a>><br>> Date:
Sunday, April 12, 2009, 6:59 PM<br>><br>> You should use an curried function as f instead of a uncurried one.<br>> Uncurried functions are rarely used in Haskell.<br>><br>> -- Lennart<br>><br>> On Sun, Apr 12, 2009 at 10:09 PM, michael rice <<a ymailto="mailto:nowgate@yahoo.com" href="/mc/compose?to=nowgate@yahoo.com">nowgate@yahoo.com</a>> wrote:<br>>> Thanks, guys!<br>>><br>>> Boy, this bunch of complemented partially applied functions gives a whole<br>>> new meaning to the term "thinking ahead." And the whole shebang is waiting<br>>> on that input integer to set everything in motion. Pretty clever.<br>>><br>>><br>>> To generalize, I changed the function to:<br>>><br>>> makeVerifier :: ((Int,Int) -> Int) -> Int -> (Int -> Bool)<br>>> makeVerifier f m = divides m . foldl (+) 0 . map f . zip [1 .. ] . digits<br>>><br>>> so, in
Haskell<br>>><br>>> let checkIsbn = makeVerifier (\ (i,d) -> i * d) 11<br>>><br>>> let checkUpc = makeVerifier (\ (i,d) -> if odd i then d else 3*d) 10<br>>><br>>> let checkCc = makeVerifier (\ (i,d) -> if odd i then d else if d < 5 then<br>>> 2*d else 2*d+1) 10<br>>><br>>> let checkUsps = makeVerifier (\ (i,d) -> if i == 1 then -d else d) 9<br>>><br>>><br>>> I think I'm catching on.<br>>><br>>> Michael<br>>><br>>><br>>><br>>> --- On Sun, 4/12/09, Daniel Fischer <<a ymailto="mailto:daniel.is.fischer@web.de" href="/mc/compose?to=daniel.is.fischer@web.de">daniel.is.fischer@web.de</a>> wrote:<br>>><br>>> From: Daniel Fischer <<a ymailto="mailto:daniel.is.fischer@web.de" href="/mc/compose?to=daniel.is.fischer@web.de">daniel.is.fischer@web.de</a>><br>>> Subject: Re: [Haskell-cafe] Functions that return
functions<br>>> To: <a ymailto="mailto:haskell-cafe@haskell.org" href="/mc/compose?to=haskell-cafe@haskell.org">haskell-cafe@haskell.org</a><br>>> Cc: "michael rice" <<a ymailto="mailto:nowgate@yahoo.com" href="/mc/compose?to=nowgate@yahoo.com">nowgate@yahoo.com</a>><br>>> Date: Sunday, April 12, 2009, 12:15 PM<br>>><br>>> Am Sonntag 12 April 2009 17:38:53 schrieb michael rice:<br>>>> The following are exercises 5.10, and 5.11 from the Scheme text "Concrete<br>>>> Abstractions" by Max Hailperin, et al. The text at that point is about<br>>>> writing verifiers to check ID numbers such as ISBNs, credit card numbers,<br>>>> UPCs, etc.<br>>>><br>>>> ======<br>>>><br>>>> Exercise 5.10<br>>>> Write a predicate that takes a number and determines whether the sum of<br>>>> its<br>>>> digits is divisible by
17.<br>>>><br>>>> Exercise 5.11<br>>>> Write a procedure make-verifier, which takes f and m as its two arguments<br>>>> and returns a procedure capable of checking a number. The argument f is<br>>>> itself a procedure of course. Here is a particularly simple example of a<br>>>> verifier being made and used.<br>>>><br>>>> (define check-isbn (make-verifier * 11))<br>>>><br>>>> (check-isbn 0262010771)<br>>>> #t<br>>>><br>>>> The value #t is the "true" value; it indicates that the number is a valid<br>>>> ISBN.<br>>>><br>>>> As we just saw, for ISBN numbers the divisor is 11 and the function is<br>>>> simply f(i,d(i)) = i * d(i). Other kinds of numbers use slightly more<br>>>> complicated functions, but you will still be able to use make-verifier to<br>>>> make a verifier much more easily
than if you had to start from scratch.<br>>>><br>>>> =======<br>>>><br>>>> Here's the Scheme check-verifier function I wrote, followed by my humble<br>>>> attempt at a Haskell function that does the same thing. Below that are<br>>>> some<br>>>> verifier functions created with the Scheme make-verifier. Admittedly,<br>>>> functions that return functions are Lispy, but perhaps there a Haskelly<br>>>> way<br>>>> to accomplish the same thing?<br>>><br>>> Functions returning functions are quite natural in Haskell.<br>>> Since usually functions are written in curried form, a function returng a<br>>> function<br>>> corresponds to a function of multiple arguments applied to only some of<br>>> them.<br>>><br>>>><br>>>> Michael<br>>>><br>>>>
===============<br>>>><br>>>><br>>>> (define (make-verifier f m) ;f is f(i,d) & m is divisor<br>>>> (lambda (n)<br>>>> (let* ((d (digits n))<br>>>> (i (index (length d)))) ;(index 3) => (1 2 3)<br>>>> (divides? m (reduce + 0 (map f i d)))))) #f<br>>>><br>>>> makeVerifier :: (Int -> Int -> Int) -> Int -> (Int -> Bool)<br>>>><br>>>> makeVerifier f m = \n -> let d = digits n<br>>>><br>>>> i = [1..(length d)]<br>>>><br>>>>
in \n -> divides m (foldl (+) 0 (map2 f i d))<br>>>><br>>>><br>>><br>>> makeVerifier f m n = divides m . foldl (+) 0 $ zipWith f [1 .. ] (digits<br>>> n)<br>>><br>>> just call makeVerifier f m to get your verification function :)<br>>><br>>> If you don't want to name the last argument:<br>>><br>>> makeVerifier f m = divides m . foldl (+) 0 . zipWith f [1 .. ] . digits<br>>><br>>> more point-freeing would be obfuscation.<br>>> Instead of foldl (+) 0, you could also just write sum.<br>>><br>>>><br>>>> -- Note: Reduce is just foldl f 0 lst, but map2 is<br>>>> map2 :: (Int -> Int -> Int) -> [Int] -> [Int] -> [Int]<br>>>> map2 f m n = [ f i d | (i,d) <- zip m
n]<br>>><br>>> map2 is zipWith, already in the Prelude.<br>>><br>>>><br>>>> -- And here's my digits function<br>>>> digits :: Int -> [Int]<br>>>> digits 0 = []<br>>>> digits n = rem n 10 : digits (quot n 10)<br>>><br>>> Unless you are desperate for speed and sure you deal only with positive<br>>> numbers (or know<br>>> that you really want quot and rem), better use div and mod. Those give the<br>>> commonly<br>>> expected (unless your expectation has been ruined by the behaviour of % in<br>>> C, Java...)<br>>> results.<br>>><br>>>><br>>>> -- And divides function<br>>>> divides :: Int -> Int -> Bool<br>>>> divides divisor n = 0 == rem n divisor<br>>>><br>>>> =====<br>>>><br>>>> (define check-isbn ;book number<br>>>>
(make-verifier<br>>>> *<br>>>> 11))<br>>>><br>>>> (define check-upc ;universal product code<br>>>> (make-verifier<br>>>> (lambda (i d) (if (odd? i) d (* 3 d)))<br>>>> 10))<br>>>><br>>>> (define check-cc ;credit card<br>>>> (make-verifier<br>>>> (lambda (i d) (if (odd? i) d (if (< d 5) (* 2 d) (+ (* 2 d) 1))))<br>>>> 10))<br>>>><br>>>> (define check-usps ;postal money order<br>>>> (make-verifier<br>>>> (lambda (i d) (if (= i 1) (- d) d))<br>>>> 9))<br>>><br>>><br>>><br>>> _______________________________________________<br>>> Haskell-Cafe mailing list<br>>> <a ymailto="mailto:Haskell-Cafe@haskell.org"
href="/mc/compose?to=Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>>> <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>>><br>>><br>><br>><br>> _______________________________________________<br>> Haskell-Cafe mailing list<br>> <a ymailto="mailto:Haskell-Cafe@haskell.org" href="/mc/compose?to=Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>> <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>><br>><br></div></blockquote></td></tr></table><br>