I'm a newbie in Haskell and I'm reading "Learn You a Haskell for Great Good!".
An expression that defines with a "name" and a "space", followed by "parameters" could be used as functions.
Consider the following code:
doubleMe = 2
this code actually follows the rule above, so we could see it as a function. but it really seems like an assign operations in java or c++.
So, How to understand the variable in Haskell?
At the top level of a program, name = expression is a definition. It creates a variable, in the sense of a mathematical variable—just a name for some expression. It can be a definition of a value:
two :: Int
two = 2
Or a definition of a function:
twice :: Int -> Int
twice x = x * two
A definition refers to a function if its type has a function arrow ->.
In a do block or GHCi, let name = expression is a local definition.
main :: IO ()
main = do
let greet name = "Hello, " ++ name ++ "!"
putStrLn (greet "world")
Finally, there is another use of the let keyword: let name = expression1 in expression2. This creates a variable local to a single expression:
length (let x = "hello" in x ++ x) == 10
Be aware that let takes a block of bindings, so it’s subject to the layout rules like other layout keywords, such as do, where, of as in case…of, and so on:
main :: IO ()
main = do
-- Bindings must be aligned past the start column.
-- ↓
let greeting name = "Hello, " ++ name ++ "!"
parting name = "Goodbye, " ++ name ++ "!"
putStrLn (greeting "world")
putStrLn (parting "world")
length $ let x = "hello"
y = "goodbye"
in x ++ y
As with other layout keywords, can instead put a newline and a fixed amount of indentation after let, and then not worry about alignment:
main = do -- ← newline+indent
let -- ← newline+indent
greeting name = …
parting name = …
…
length $ let
x = "hello"
y = "goodbye"
in x ++ y
Or you can always include explicit curly braces and semicolons:
main :: IO ();
main = do {
let {
greeting name = "Hello, " ++ name ++ "!";
parting name = "Goodbye, " ++ name ++ "!";
};
putStrLn (greeting "world");
putStrLn (parting "world");
};
length $ let {
x = "hello";
y = "goodbye";
} in x ++ y
Related
I was wondering, how can we do multiple things in a Haskell function?
For example, I have this code:
number = 0
increment :: Int -> Int
increment i = i + 1
function :: String -> String
function s = s ++ " world" AND increment number
I was wondering, how can we do something like this? I'm searching everywhere but I don't find a solution for this simple example :O
number
0
:function "hello"
"hello world" (AND the number = 1 now)
number
1
note: I know that AND is not a syntax in Haskell but I wanted to make you understand what I wanted to say :)
You can't modify variables in Haskell (they are not, in fact, variable). What you can do is return new values:
f (string, number) = (string ++ " world", number + 1)
which would be used like this:
Prelude> f ("hello", 0)
("hello world",1)
If you called this function with a variable instead of a literal, it would not change the value of that variable, because Haskell is designed to prevent that from happening:
Prelude> let n = 0
Prelude> f ("hello", n)
("hello world",1)
Prelude> print n
0
the problem is: in haskell you don't have "mutable states" like in other programming languages: so "number = 1" wouldn't work in terms of "setting a State"
you could combine them as a result:
increment :: Int -> Int
increment i = i + 1
stringCombine :: String -> String
stringcombine str = str ++ "world"
combine i str = (increment i, stringCombine str)
or if you have a function with a side effect (like print, putStrLn) you have to use the IO Monad:
doSideEffects :: Int -> String -> IO Int
doSideEffects i str = do
putStrLn $ str ++ "world"
return $ increment i
Can't get my haskell program to work
sort [] = []
sort (x:xs) = sort [a | a <- xs , a<=x ] ++ [x] ++ sort [a | a <- xs , a > x]
getList:: Int->[IO Int]
getList 0 = [] --declaring the empty list
getList n = [a | a <- [getNumber] ] ++ getList (n-1)
getNumber::IO Int --get number function
getNumber = do
s <- getLine
return (read s)
--Main function to handle
main = do
p <- getNumber -- taking the number of variable
lst <- sequence (getList p) --calling gtlistFunction to input the list
print (sort lst) --print
Error:
quicksort.hs:13:6: error:
parse error on input `='
Perhaps you need a 'let' in a 'do' block?
e.g. 'let x = 5' instead of 'x = 5'
|
13 | main = do
| ^
You must indent all do-blocks:
-- NOT correct: this will fail
main = do
putStrLn "This is..."
putStrLn "WRONG!"
-- Correct:
main = do
putStrLn "This is..."
putStrLn "correct!"
The number of spaces doesn't matter as long it is consistent.
To avoid this you could use c-like notation:
-- Also correct:
main = do {
putStrLn "This is...";
putStrLn "also correct!";
}
And this leaves you free to indent as you like. Example:
-- Also correct:
main = do
{ putStrLn "This is..."
; putStrLn "also correct!"
;}
Without indentation, the parser doesn't know that main = ... starts a new definition, separate from the preceding definition of getNumber. The following would work fine:
getNumber::IO Int
getNumber = do
s <- getLine
return (read s)
main = do
p <- getNumber
lst <- sequence (getList p)
print (sort lst)
The transition from one-space indentation to no indentation is enough to tell the parser that return (read s) is the last line of the do block defining getNumber, and that main = do is the beginning of a new top-level definition.
Either indenting your code, or using the explicit brace syntax in AJFarmar's answer, lets the parser know where one definition ends and the next begins.
I tried various combinations to fix the indentation for the following code but failed. How shall i fix the below
fold' list = do
let result = foldl (+) list
in putStrLn $ "Reduced " ++ show(result)
return $ result
parse error on input `in'
Failed, modules loaded: none.
In a do clause, the in keyword should not be used.
So you can fix it with writing:
fold' list = do
let result = foldl (+) list
putStrLn $ "Reduced " ++ show(result) -- no "in" keyword
return $ result
The scope of the let statement is the rest of the clauses.
The translation is like specified in section 3.14 of the Haskell report [link]:
do {e} = e
do {e;stmts} = e >> do {stmts}
do {p <- e; stmts} = let ok p = do {stmts}
ok _ = fail "..."
in e >>= ok
do {let decls; stmts} = let decls in do {stmts}
So in case we define two let statements with the same name (which is not recommended), the first one moving to the top will count.
So for:
foo = do
let x = "4"
putStrLn x
let x = "2"
putStrLn x
It will translate into:
foo = let x = "4" in (putStrLn x >> (let x = "2" in putStrLn x))
So the first putStrLn will use the x defined by let x = "4" whereas the last one will use the x defined in let x = "2".
I am currently working 99 haskell problems
I cannot understand why am I getting an error in this function :-
repli :: [a] -> Int -> [a]
repli xs n = concatMap (take n . repeat) xs
If you are using the REPL, try
>>> let repli xs n = concatMap (take n . repeat) xs
Writing Haskell in the REPL (ake GHCi) is a bit different to writing it in a file. For one thing, variable bindings and function definitions have to be prefixed with let as in
>>> let a = 1
>>> let f x = x + a
For another, you generally have to enter definitions all on one line. You can separate separate definitions with a semicolon, like this
>>> let a = 1; b = 2
or you can use multi-line mode, like this
>>> :{
>>> let c = 3
>>> d = 4
>>> :}
If you've learnt about monads (have you?) then you can imagine that everything you write in the REPL is part of a do block which is of type IO (), with the statements executed as you type them. So in a file you might write
main :: IO ()
main = do
name <- getLine
let greeting = "Hello " ++ name ++ "!"
putStrLn greeting
whereas in the REPL you would write
>>> name <- getLine
Chris
>>> let greeting = "Hello " ++ name ++ "!"
>>> putStrLn greeting
Hello Chris!
>>>
I'm a newbie in Haskell and I'd like some opinions about improving this script. This is a code generator and requires a command line argument to generate the sql script.
./GenCode "people name:string age:integer"
Code:
import Data.List
import System.Environment (getArgs)
create_table :: String -> String
create_table str = "CREATE TABLE " ++ h (words str)
where h (x:xs) = let cab = x
final = xs
in x ++ "( " ++ create_fields xs ++ ")"
create_fields (x:xs) = takeWhile (/=':') x ++ type x ++ sig
where sig | length xs > 0 = "," ++ create_fields xs
| otherwise = " " ++ create_fields xs
create_fields [] = ""
type x | isInfixOf "string" x = " CHARACTER VARYING"
| isInfixOf "integer" x = " INTEGER"
| isInfixOf "date" x = " DATE"
| isInfixOf "serial" x = " SERIAL"
| otherwise = ""
main = mainWith
where mainWith = do
args <- getArgs
case args of
[] -> putStrLn $ "You need one argument"
(x:xs) -> putStrLn $ (create_table x)
I think you understand how to write functional code already. Here are some small style notes:
Haskell usually uses camelCase, not under_score_separation
In create_table, cabo and final are not used.
Usually a list-recursive function like create_fields puts the empty list case first.
I would not make create_fields recursive anyway. The comma-joining code is quite complicated and should be separated from the typing code. Instead do something like Data.List.intercalate "," (map create_field xs). Then create_field x can just be takeWhile (/=':') x ++ type x
Especially if there are a lot of types to be translated, you might put them into a map
Like so:
types = Data.Map.fromList [("string", "CHARACTER VARYING")
,("integer", "INTEGER")
-- etc
]
Then type can be Data.Maybe.fromMaybe "" (Data.Map.lookup x types)
Code can appear in any order, so it's nice to have main up front. (This is personal preference though)
You don't need mainWith.
Just say
main = do
args <- getArgs
case args of
[] -> ...
You don't need the dollar for the calls to putStrLn. In the first call, the argument wouldn't require parentheses anyway, and in the second, you supply the parentheses. Alternatively, you could keep the second dollar and drop the parentheses.
Don't use length xs > 0 (in sig); it needlessly counts the length of xs when all you really wanted to know is whether it's empty. Use null xs to check for a non-empty list:
...
where sig | null xs = ... -- Empty case
| otherwise = ... -- Non-empty case
or add an argument to sig and pattern match:
...
where sig (y:ys) = ...
sig [] = ...
Although Nathan Sanders' advice to replace the whole recursive thing with intercalate is excellent and makes this a moot point.
You're also identifying the type by passing the whole "var:type" string into type, so it is testing
"string" `isInfixOf` "name:string"
etc.
You could use break or span instead of takeWhile to separate the name and type earlier:
create_fields (x:xs) = xname ++ type xtype ++ sig
where
(xname, _:xtype) = break (==':') x
sig = ...
and then type can compare for string equality, or look up values using a Map.
A quick explanation of that use of break:
break (==':') "name:string" == ("name", ":string")
Then when binding
(xname, _:xtype) to ("name", ":string"),
xname -> "name"
_ -> ':' (discarded)
xtype -> "string"