1. Rewrite the following expressions using Haskell function call syntax. Use as few parentheses as possible.

    f(x) * a == g(a) + c
        
    h(f(a) + g(x-y))
        
    f(g(a*-b)-h(b))
    
    f(x) * a == g(a) + c
        f x * a == g a + c
    	
    h(f(a) + g(x-y))
        h (f a + g (x - y))
    	
    f(g(a*-b)-h(b))
        f (g (a * (-b)) - h b)
        More idiomatic: f (g (a * negate b) - h b )
    
  2. Try :info on these types/type classes: Eq, Bool, Int, Ord, Bounded. Several end in many lines of this general form: instance (Eq a, Eq b, Eq c) => Eq (a, b, c). Ignore that stuff for now. Focus on what precedes it.

  3. Try :type on the following functions: even, id, pred, abs, signum, log, and logBase. Then try some calls to the functions.

  4. What does pred 'A' produce, and why?

    Also, see if you can find an argument for pred that will produce this exception: Prelude.Enum.Char.pred: bad argument

    Re pred 'A', before I started memorizing the ASCII codes I usually did man ascii to answer questions like that. There are also lots of ASCII charts on the web. One is http://www.asciitable.com

    Re making pred blow, there's nothing before the first character, which has a numeric value of zero. In Haskell string literals we can use \N in a character or string literal to specify the Nth Unicode character. (The first 128 characters of Unicode are the same as ASCII.) Haskell also recognizes ASCII mnemonics like NUL and BEL, too.

    > pred '\0'
    *** Exception: Prelude.Enum.Char.pred: bad argument
    
    > pred '\NUL'
    *** Exception: Prelude.Enum.Char.pred: bad argument
    

    p.s.
    I started memorizing the ASCII codes about 35 years after I should have. I hope you'll start sooner than I did! Here's one way to learn them: http://www.memrise.com/course/80243/ascii-to-decimal

  5. As shown on slide 45, use :m Data.Char to load the Data.Char module and then do :browse (no arguments) to see all the functions in the module. Try ord, chr, isPunctuation, isHexDigit, and toTitle. Regarding values for ord and chr, Google for ASCII chart.

  6. Hoogle searches Haskell documentation. For example, hit http://www.haskell.org/hoogle/?hoogle=toUpper to search for functions named toUpper. (Suggestion: Set up a Chrome "Search Engine" for Hoogle. Slide 28 in http://www.cs.arizona.edu/classes/cs337/fall13/files/html.pdf has a skimpy how-to. The Firefox analog is "keywords".)

  7. Try :type pi and :type minBound. Are they functions?

  8. Try these expressions, which use :: to request that the value have a specific type.

    minBound::Char
    maxBound::Bool
    maxBound::Int
    maxBound::Integer (it's an error, but why?)
    
  9. Try the function definitions on slide 64 and then write some single-argument functions:

    We haven't seen if-else or guards, so define the above using only operators, which are on slide 80. Try defining some using let at the ghci prompt. Define others by loading them from a file (and leaving off the let!) Use :set +t to cause the type of each to be automatically shown.
    isZero1 x = x == 0
    
    isZero2 x = x == 0.0
    
    isNonZero x = not (isZero1 x) -- note use of not
    
    ltRecip x = x < recip x
    
    ltSelf x = x < x
    
    isIOU c = c == 'I' || c == 'O' || c == 'U'
    
    notIsIOU c = not (isIOU c) -- note use of not
    
    area r = pi * r ^ 2
    
  10. If you didn't experiment with indentation (slide 75) on the previous question, try that now.

  11. Get creative: Think up three more significantly different single-argument functions.

  12. The material on partial applications is critical! If you haven't worked through the examples on slides 68-73, do that now!!!

  13. Create functions log2 and log10 using partial applications of logBase.

  14. The last example on slide 29 looks like string concatenation but we'll learn that there's more to it than just that. See if you can use ++ to create a function wrap that behaves like this:

    > wrap "(" ")" "abc"
    "(abc)"
    
    > let parens = wrap "(" ")"
    
    > let brackets = wrap "<" ">"
    
    > parens (brackets (parens "123"))
    "(<(123)>)"
    
    If you succeed, use :t to check the type of wrap, parens, and brackets.
    let wrap before after text = before ++ text ++ after
    

    Note that parens and brackets are partial applications, with matching parentheses and brackets, respectively, plugged-in ("wired-in").

  15. Think up a good real-world analogy for partial application.

  16. If you know JavaScript, create a JavaScript version of add from slide 69. The expression add(3)(4) should produce 7.

    function add(x) {
        return function (y) { return x + y }
        }
    
  17. Look through some old code you've written—Java or whatever—and see if you can find some cases where the ability to use a partial application might have saved some repetition. If you know C, think about fprintf.

  18. Define functions f1 through f6 whose types are inferred to be the following. The functions don't need to perform any meaningful computation—only the type matters. You may NOT use <i>::type</i> (as shown on slide 68) to force types.

    f1 :: Eq a => a -> Bool
    
    f2 :: Num a => t -> a
    
    f3 :: Fractional a => t -> a
    
    f4 :: Int -> Int
    
    f5 :: (Bounded a, Ord a) => a -> Bool
    
    f6 :: (Bounded a, Eq a) => a -> Bool
    
    let f1 x = x == x
    
    let f2 x = 10
    
    let f3 x = 1.0
    
    let f4 x = ord 'a' + x -- assumes ':m +Data.Char' done previously or in ~/.ghci
    
    let f5 x = x > minBound
    
    let f6 x = x == minBound
    
  19. Get creative: Imagine a function type and then write a function that will be inferred to have that type. Do two more.

  20. Slide 56 shows a big red "X" on the arrow from Eq to Num.

    Use :info on Ord, Num, and Real, and see if you believe my "correction" is correct.

  21. See if you can find a REPL for Java. If you find one, be sure to try it and see how well it works!

  22. See if you can make some progress on the last two questions on slide 49 (re REPLs). (TOUGH!)

  23. I claim that a Java program can't do anything meaningful without using side effects but a C program can. If you know C, see if you can figure out what I might have in mind.

    Start with this. Here's a C expression with no side-effects: atoi(argv[1])

    Next, think about the warning produced by this:

    int main(int argc, char **argv)
    {
        3+4;
    }
    

    if-else, for, while, etc. aren't much use because there's no way to get a value out of them—they just orchestrate side effects. All you've got to change the flow of control is the conditional operator (expr ? v1: v2).

    A student asked, "Would a statement not be a "side effect" as long as a new value is created and that is what is used?"

    Something like this is fine:

    int i = 3;
    int j = 4;
    int k = f(i,j);
    

    We can view those *initializations* like i = 3 in a .hs file -- we can bind a name to a value once but if we do it again we get an error about multiple declarations. What we can do in Haskell is sometimes called "single assignment". I haven't yet mentioned this in class but the Haskell 2010 report calls x in "x = 3" a variable! However, there's no variability! :)

    f() (above) might be something like this:

    int f(int a, int b)
    {
        return a + b * 3;
    }
    

    We might continue with

    int x = k + (f(k,i) > 0 ? 10 : 20);
    

    Note that memory allocation is a problem. We can allocate memory,

    int *p = malloc(sizeof(int));
    
    but then we're stuck! Something like *p = 10 clearly has a side effect.

    Take a look at Haskell slide 140, too.

    See if you can take it from here, but feel free to ask me more.

    Remember: I claim that C can do a useful computation without any side effects but Java can't.