Monday, August 13, 2012

Haskell Chapter 1.2

"I'm the operator with my pocket calculator!" -- Kraftwerk


On Basic Operators and Calculators

    Most first-semester programming students know enough about computer-languages to understand that each language has operators -- which are miniature programs that are 'built-in' to the language. There are, of course, a whole library of operators around which the programming language is built. In many ways, the process of learning to program revolves around learning to expertly use the most crucial operators of the given language. 

    In this text I will attempt to explain operators and basic data-types that apply specifically to the lessons at hand. However, since this text is also an attempt to implement scaffolding in literary form, those operators and data-types should provide the student with a well-rounded set of tools which can be used to explore their own extra-curricular questions and experiments.

Basic Data-Types

Numbers
    The Number or 'Num' is the most basic data-type. There are different types of Num: Integers, Floats, Ints, Doubles and variables as well as a few less common types. We will mainly use three types: Integers, Floats and variables. Variables are a 'universal type' in that they are merely memory slots with no type of their own; that leaves us to Integers and Floats. You should already know what an Integer is. A float is just a decimal of some sort; called Float because that decimal can 'float' around depending on the accuracy specified by the programmer. The important characteristic of numbers or Nums, is that you can perform all sorts of mathematical operations on them. However, you cannot do this with Strings or Chars. This is an important distinction because a Char can be ANY symbol at all; including a number. 

Characters
    The Character type is any symbol you can find on your keyboard. These symbols are standardized by an organization called ASCII. They have a binary value, which you can manipulate to create some interesting text-processing modules. However, they are mostly meaningless to Haskell. Characters are there for the reader to read. In order to perform arithmetic on a Char, you need to convert it to a number first using an operator like 'read' -- which we will read about later.

Strings
    Strings are lists of Characters. As such, they are the first lists you will use in this text. There are different types of lists. Lists have there own large set of operators; and all of those operators work on Strings in the same way. Lists are complicated enough that they need their own Chapter to do them justice. However, for now just remember that Strings are really just special lists which consist of 2 or more Chars. Instead of the brackets used in other types of lists, Strings are enclosed by double-quotation marks. 

Variables
    Variables are different from Chars because they don't use quotation marks or any special IO operators. A variable is just a label for a memory slot in which you can deposit values for later use. Other than that, they are identical to variables in algebra and thus take on the characteristics of whatever data you put into them. Variables should always be given descriptive names. Avoid variable-names like x or y. In real-world scripts, terse variable names will drive you crazy and significantly reduce your productivity.

Literals
    Literals are anything other than a String or Char. Numbers and Bools are literals. Literals are what we use in the language of mathematics. Strings and Chars are what we use in human languages like English.

Bools
    Bools consist of two symbols: True and False. Written just like that, always with the first letter capitalized. As you probably already know, Bools are the core units of Logic. Either a statement is True or False. Bools are also great for running tests: 'if x is higher than 100, return True'.

GHCI the Calculator

    One of the best things about having an interactive programming environment, like GHCI, is that it allows you to utilize the power of the language on-the-fly. You can perform complex algebraic calculations on Nums that would put a top-of-the-line graphing calculator to shame. You can also test out and casually use a whole library of interactive modules by simply loading the necessary module. As a result, the environment itself becomes a tool for learning and troubleshooting. 

    Below is an explanation of some of the most common operators and the syntax required to use them. Open up your favorite text editor and give them a try as you read. If you have a Linux OS, you can right-click on the terminal and select 'Always On Top'. This will allow you to view and scroll the background blog-text while working within the terminal. If you have an Ubuntu variant of some sort, you can probably  set the transparency of the terminal window too. This allows you to see any text which runs behind the terminal window -- very handy.

    Before we get to the good stuff, there is one final concept behind operators which we must explain. There are three types of basic operators: Inline, Infix, and Modified. 
  • Infix Operators are the most familiar type of operator. Examples include most of the common arithmetic operators like add ('+'), multiply ('*'), and exponentiate ('^'). If you want to find the square of two you type '2^2' at the GHCI prompt ('Prelude>'). Infix operators go between the values you are calculating: 'Prelude> 2 * 2'
  • Inline Operators are a little less common. These work much the same as an algebraic function. Inline operators always come at the beginning of the operation. The values which you plug in to an operator are called 'arguments'. Those arguments come after the inline operator you are using. A good example is the modulo or remainder operator. This nifty tool allows you to find only the remainder produced by dividing two numbers. It is used like this: ' mod 4 2 '. Here we are trying to find out if there is any remainder left after we divide four by two. The answer is, of course, zero. 'Prelude> mod 4 2
  • Modified Operators can be either Infix or Inline. This is helpful when you want to make a piece of code more readable. You can modify any operator by placing the modifier symbol ( ` ) directly before and after the operation you are trying to modify. Notice that this is NOT the same symbol as the single-quote, which looks like this: ( ' ). You could modify the modulo operation so that the dividend comes first, the modulo operator comes second, and the divisor comes last; just like you would do in formal mathematical notation: 'Prelude> 4 `mod` 2'  
     We won't waste time specifically stating whether something is Infix or Inline, unless it is not immediately apparent or it needs to be modified to facilitate the flow of the code. Usually you can tell by looking at the example.

    We'll start with: 

    Arithmetic Operators
  • Add: +
  • Subtract: -
  • Multiply: *
  • Divide: div x y 
  • Exponentiate: ^
  • Square-Root: sqrt x
  • Modulo: mod x y
  • Associate: ( )
    OK, so there's not much in arithmetic which is different than what you or any grade-school student are already used to. Of course, there are others not listed here. For example, '/' can be used to divide literals (Nums that are not in variable-form). However, 'div' is more versatile. Checkout www.Haskell.org for complete lists of 'Prelude' operators.

Basic IO Operators

    Now we will move on to IO operators because you will need them in the next section. IO operators just send an output (whatever you decide) to the screen. In this case, they send it to the onscreen display of the terminal. 
    Most IO operators deal with 'Strings'. Strings are just groups composed of Characters or Chars. Haskell has no ability to find meaning in Strings unless you write a program telling it how. So, to Haskell the Char '2' has the same meaning as the Char 'P'. This is important to remember. In later exercises, this knowledge is crucial. We'll start with the two most basic IO operators: 'getLine' and 'putStrLn':

IO Operators for Strings and Chars
  • getLine This is an input command -- as opposed to an operator. This command has no arguments. If you put getLine into a module, Haskell will stop what it is doing, record any keyboard input until the user presses enter, and immediately spit-out that input in the form of a String. If you enter a number into getLine, it will spit it out as a String, so Haskell won't know that it is actually a number.
  • putStrLn This is an output operator. It takes only one argument which must be enclosed in double-quotations. I find it is best to use putStrLn with parens like this: ' putStrLn ("Hello World!")'. putStrLn automatically displays the argument you give it in the terminal screen; without displaying the double-quotes or parens. One crucial rule to remember when using putStrLn is that it only accepts two kinds of argument: Strings and literals. If you try to sneak a function into the output of putStrLn, your module will fail to load!
  • <- This is the IO-Bind operator. This is a special operator which is mostly used with IO operations. It takes the output of any IO function, IO command, or IO operator and saves it to a variable-name of your choosing. So, if you write 'name <- getLine' in a script, it will run getLine and pipe the output into the variable 'name'. This is how you save important IO values for future use.
  • ++ This is the join or Concatenate Operator. This allows you to join two strings together. This is usually used in an instance of 'putStrLn'; inside the parens but outside of double-quotations. Remember that last sentence. This is crucial when you are using Concatenate: ++ Goes inside of parens but outside of quotes.
  • read This is not really an IO operator at all. However, you almost always use read in conjunction with some previous IO operation. So I include it here. 'read' converts a Character into a number. This is a vital operator. If you use getLine to retrieve a number from the user, getLine will save that number as a  Char or String of Chars. The problem is that arithmetic operators do not work on Chars! They only work on Numbers! So, use read (inline) in order to convert a Char into a Number just long enough to perform an operation on it. Once the operation is done, the variable containing the Char will revert to it's original state. There's one more rule about 'read' which you must understand in order to use it correctly: you must avoid using read in the argument of a function. This is because read changes the type of the argument and, as we have already learned, Haskell is based on a static (unchanging) type system. It is better to use read inside the definition of a function; where the rule is generally 'anything goes'.
  • let This is also not exactly an IO operator. However, you do use it to input and save data to a variable within ghci or within a function. It is a Bind Operator like the arrow ( <- ). Try this: 'Prelude> let x = 9'. Now you can add x, multiply, subtract or use any other one of the arithmetic operators on x. In this way we have 'declared the variable x'. That is, we declared that x is the name of a memory slot which we want to save data in. The stupid thing about 'let' is that we can't always use it in scripts (modules). For instance, for variable declarations which occur outside of a function and within a script, you simply type 'x = whatever'. This is also the case with 'Where' clauses, which we will learn about later. Because of this confusing inconsistency, I sincerely hope that the Glasgow Haskell folks will eliminate 'let' in the future. For now, we just need to remember that 'let' is only used within ghci and the body of functions. 'let' is only designed for non-IO applications like arithmetic functions and variable declarations.
    For the moment, don't worry too much about IO operations. Instead, try using ghci as a simple calculator. Open up an old algebra book and try out some problems which use variables and parens. Use the 'let' operator to deposit values into variables and test the results. You will find that parentheses (parens) work the same in Haskell as they do in your algebra textbook. Haskell is designed to use as much mathematical notation as possible. This makes it familiar and easy to use for anyone with secondary-school education under their belt.

Warm-Up Exercises
  • Use ghci as a basic calculator using the arithmetic operators above.
  • Use 'let' to declare a variable. Try performing different arithmetic operations on the variable.
  • Try-out some basic problems from an old algebra text which make use of variables and parens.
  • Find the most difficult order of operations problem you can and calculate it in ghci. Check the results.
  • Use 'putStrLn' using the rules listed above in order to display 'Hello World' within ghci.
  • Use 'getLine', '<-' and the variable 'n'  to save your numeric keyboard input.
  • Use 'read n' with the arithmetic operators listed above. Use parens to insert 'read n' into the arguments of Inline operators -- just as you would in formal mathematical notation.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.