slides made with reveal.js
http://lab.hakim.se/reveal-js
Learn at least one new language every year.- The Pragmatic Programmer, p14
Can't mix types or use undefined variables
Prelude> a
<interactive>:1:1: Not in scope: `a'
Prelude> (1 :: Integer) + (1 :: Double)
<interactive>:1:19:
Couldn't match expected type `Integer' with actual type `Double'
...
Must convert before adding
Prelude> read "3" + 1
4
Type inference
Prelude> read "3" + 1.0
4.0
Prelude> read "3"
<interactive>:1:1:
Ambiguous type variable `a0' in the constraint:
...
Prelude> read "3" :: Double
3.0
Undefined constant becomes string and you get:
php > echo UNDEFINED_PHP_CONST + 900;
900
With PHP notices on:
php > echo UNDEFINED_PHP_CONST + 900;
PHP Notice: Use of undefined constant UNDEFINED_PHP_CONST - assumed 'UNDEFINED_PHP_CONST' in
php shell code on line 1
900
quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
where
lesser = filter (< p) xs
greater = filter (>= p) xs
function process_with_clean_environment($do_process) {
// backup existing session
$current_data = $_SESSION['data'];
// call function
$do_process();
// restore
$_SESSION['data'] = $current_data;
}
process_with_clean_environment(function() {
// do whatever I want with $_SESSION['data']
});
Necessary due to existing code difficult to reuse
filter is_this_good the_list
$result = array_filter($the_list, "is_this_good");
vs
$result = array();
foreach ($the_list as $element) {
if (is_this_good($element)) {
$result[] = $element;
}
}
return $result;
Prelude> let the_list = [1, 3 .. 7]
Prelude> the_list
[1,3,5,7]
Prelude> {- map applying lambda to the_list -}
Prelude> map (\x -> x + 1) the_list
[2,4,6,8]
Prelude> {- aka "reduce" down to a single result -}
Prelude> foldl (+) 0 the_list
16
array_map,
array_reduce
See array functions.
Prelude> toUpper . head . tail $ "Me"
'E'
Prelude> toUpper (head (tail "Me"))
'E'
Prelude> let uppercase = toUpper . head . tail
{- Project Euler Problem #1 -}
{- Find the sum of all natural numbers below 1000 and are multiples of 3 or 5 -}
sum [x | x <- [1 .. 999], x `mod` 3 == 0 || x `mod` 5 == 0]
Keep things separated via type system:
Prelude> {- getLine returns IO String of what user types -}
Prelude> :type getLine
getLine :: IO String
{- A pure function -}
uppercase :: String -> String
uppercase str = map toUpper str
{- Trying to stuff a IO String to String will fail -}
main = do
return $ uppercase getLine
{- Take String out of IO String first, then you can use it -}
main = do
str <- getLine
return $ uppercase str
Careful that function can have side effects:
function bad_php_code() {
global $db;
$data = $_SESSION['data'];
$_SESSION['data'] = 0;
}
makes it difficult to test or reuse
add_if_greater a = if a > 100
then a + 1
add_if_greater a = if a > 100
then a + 1
else a
Be careful with:
// code in our codebase
function mixed_return() {
if (!good) {
return FALSE;
}
perform_action();
// PHP returns NULL for you
}
$result = mixed_return();
if (!$result) {
// Both cases are "false"
}
// forced to distinguish
if ($result === FALSE) {
}
Defining a type:
{- Type with 2 value constructors -}
data Maybe a = Just a
| Nothing
{- Using value constructors -}
let result = Just 1
let result = Nothing
Think of this like an interface
class Eq a where
(==) :: a -> a -> Bool
Actual implementation of == for Integer & Float
instance Eq Integer where
x == y = x `integerEq` y
instance Eq Float where
x == y = x `floatEq` y
More at Haskell wiki
/ HomeR GET
/echo/#Text EchoR GET
aka Controller
getEchoR :: Text -> Handler RepHtml
getEchoR theText = do
defaultLayout $ do
$(widgetFile "echo")
aka View
<h1> #{theText}
templates/echo.hamlet
storage (DB, etc)
{- Define a Developer datatype -}
mkPersist sqlSettings [persist|
Developer
firstname String
lastname String
deriving Show
|]
{- Add a developer -}
main = withSqliteConn ":memory:" $ runSqlConn do
dannyId <- insert $ Developer "Danny" "Su"