Defining variables inside a function Haskell - haskell

I am a huge newbie to Haskell, I actually just started 10 minutes ago. I am trying to figure out how to define a variable inside a function. Lets say I have the function
foo :: Int -> Int
foo a =
b = a * 2
b
-- Yes, I know, it doesn't do anything interesting
When I run it in GHCi I get a syntax error! How can you define a variable inside a function?

There are two ways to do this:
foo a = b where b = a * 2
foo a = let b = a * 2 in b
In most cases, the choice between them is an aesthetic rather than technical one. More precisely, where may only be attached to definitions, whereas let ... in ... may be used anywhere an expression is allowed. Both where and let introduce blocks, making multiple internal variables convenient in both cases.

Disregarding technical correctness, the answer is "sort of".
I think it's better to think of a variable as a function of zero arguments evaluating to a given value.
module Main where
import System.IO
foo :: Integer -> Integer
foo a =
b where
b = a * 2
main = do
putStrLn $ show $ foo 10

Related

Misconception on Type Classes and variable assignment in Haskell [duplicate]

This question already has answers here:
Why can a Num act like a Fractional?
(4 answers)
Closed 3 years ago.
Very new to Haskell and trying to understand how type classes and variables interact.
My first thing to play with was:
i :: a; i = 1
My expectation was that, since i was typed as generically as possible, I should be able to assign absolutely anything to it. (I know that I probably can't do anything with variable i, but that wasn't important.)
But, I was wrong. The above gives an error and requires that it be:
i :: Num a => a; i = 1
After playing around a bit more I came up with the following:
g :: Num a => a -> a; g a = a + 1
g 1
(returned 2)
gg :: Num a => a; gg = g 1
gg
(returned 2)
Ok... so far so good. Let's try a Fractional parameter.
g :: Num a => a -> a; g a = a + 1
g 1.3
(returned 2.3)
gg :: Num a => a; gg = g 1.3
(error)
So, please... what is it about variables that causes this? From a non-functional programming background, it "looks" like I have a function that returns a value with a type implementing Num and tried to assign it to a variable with a type implementing Num. Yet, the assignment fails.
I'm sure this is some basic misconception I have. It's probably the same thing that prevents the first example from working. I really want to get it straightened out before I start making far more serious conceptual errors.
i :: a; i = 1
My expectation was that, since i was typed as generically as possible, I should be able to assign absolutely anything to it. (I know that I probably can't do anything with variable i, but that wasn't important.)
No, it's the other way around. The type represents how that value can be used later on, i.e. it states that the user can use i pretending that it is of any type that might be required at that time. Essentially, the user chooses what the type a actually is, and the code defining i :: a must conform to any such choice of the user.
(By the way we usually call i = 1 "binding" or "definition", not "assignment" since that would imply we can reassign later on.)
gg :: Num a => a; gg = g 1.3
(error)
The same principle applies here. gg claims to be of any numeric type the user might want, but if the user later on chooses, say, Int the definition g 1.3 does not fit Int.
The user can choose the type using an explicit signature (print (gg :: Int)), or putting it into context that "forces" the type (print (length "hello" + gg) forces Int since length returns Int).
If you are familiar with "generics" in some other languages, you can draw a comparison with this code:
-- Haskell
i :: a
i = 1 -- type error
-- pseudo-Java
<A> A getI() {
return 1; -- type error
}
From a more theoretical perspective, you are thinking of the wrong quantifier. When you write i :: a, you are thinking i :: exists a . a (not a real Haskell type) which reads as "i is a value of some type (chosen at definition time)". Instead in Haskell i :: a means i :: forall a . a which reads as "i is a value of all types (any type that might be needed on use)". Hence it boils down to "exists" vs "forall", or to "who chooses what type type a actually is".

What does immutable variable in Haskell mean?

I am quite confused with the concept of immutable variables in Haskell. It seems like that we can't change the value of variables in Haskell. But when I tried following code in GHCI, it seemed like the value of variables did change:
Prelude> foo x=x+1
Prelude> a=1
Prelude> a
1
Prelude> foo a
2
Prelude> a=2
Prelude> a
2
Prelude> foo a
3
Does this conflict with the idea of immutable variables?
Many thanks!
Haskell doesn't allow you to modify existing variables. It does, however, allow you to re-use variable names, and that's all that's happening here. One way to see this is to ask GHCi, using the :i[nfo] directive, where the variable was declared:
Prelude> let a = 1
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:2:5
Prelude> let a = 2
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:4:5
These are actually two entire seperate, different variables, which just happen to be called the same name! If you just ask for a, the newer definition will be “preferred”, but the old one is still there – one way to see this, as remarked by chi in the comments, is to use a in a function:
Prelude> let a = 2
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:4:5
Prelude> let f x = a + x
Prelude> let a = 3
Prelude> f (-2)
0
f never needs to care that you've defined a new variable that's also called a; from its perspective a was one immutable variable that always stays as it is.
It's worth talking a bit about why GHCi prefers the later definition. This does not otherwise happen in Haskell code; in particular if you try to compile the following module, it simply gives an error concerning duplicate definition:
a = 1
a = 2
main :: IO ()
main = print a
The reason that something like this is allowed in GHCi is that it works different from Haskell modules. The sequence of GHCi commands forms in fact a sequence of actions in the IO monad†; i.e. the program would have to be
main :: IO ()
main = do
let a = 1
let a = 2
print a
Now, if you've learned about monads you'll know that this is just syntactic sugar for
main =
let a = 1 in (let a = 2 in (print a))
and this is really the crucial bit for why you can re-use the name a: the second one, a = 2, lives in a narrower scope than the first. So it is more local, and local definitions have priority. Whether this is a good idea is a bit debatable; a good argument for it is that you can have a function like
greet :: String -> IO ()
greet name = putStrLn $ "Hello, "++name++"!"
and it won't stop working just because somebody defines elsewhere
name :: Car -> String
name car | rollsOverAtRightTurn car = "Reliant Robin"
| fuelConsumption car > 50*litrePer100km
= "Hummer"
| ... = ...
Besides, it's really quite useful that you can “redefine” variables while fooling around in GHCi, even though it's not such a good idea to redefine stuff in a proper program, which is supposed to show consistent behaviour.
†As dfeuer remarks, this is not the whole truth. You can do some things in GHCi that aren't allowed in an IO do-block, in particular you can define data types and classes. But any normal statement or variable definition act as it were in the IO monad.
(The other answer using GHCi is fine but to clarify it is not specific to GHCi or monads...)
As you can see from the fact that the following Haskell program
main =
let x = 1 in
let f y = x + y in
let x = 2 in
print (x * f 3)
prints 8 rather than 10, variables can only be "bound", not "mutated", in Haskell. In other words, the program above is equivalent (called α-equivalent, meaning a consistent change of the names of bound variables only; see https://wiki.haskell.org/Alpha_conversion for more details) to
main =
let x1 = 1 in
let f y = x1 + y in
let x2 = 2 in
print (x2 + f 3)
where it is clear that x1 and x2 are different variables.

Different numbers of arguments when pattern matching Maybe

I've run into a problem I don't really understand. I thought that I would be able to write code like this in Haskell:
foo :: Maybe Int -> Int
foo Nothing = 0
foo Just x = x
But when I try to compile it, I get the error:
Equations for ‘foo’ have different numbers of arguments
I can fix it by changing my code to the following:
foo :: Maybe Int -> Int
foo Nothing = 0
foo (Just x) = x
Which makes me think that GHC is interpreting Just as an argument to foo. But Haskell forbids using uppercase letters to start variable names, so I wouldn't think there should be any ambiguity here. What's going on?
You're correct, there's not ambiguity about whether or not Just is a constructor – but constructors can have no arguments! Haskell's pattern matching doesn't look up the names involved, it's strictly syntactic, and foo Just x = x is a perfectly well-formed function definition clause. It's ill-typed:
Prelude> let foo Just x = x
<interactive>:2:9:
Constructor ‘Just’ should have 1 argument, but has been given none
In the pattern: Just
In an equation for ‘foo’: foo Just x = x
but with different data types around, it'd be fine:
Prelude> data Justice = Just
Prelude> let foo Just x = x
Prelude> :t foo
foo :: Justice -> t -> t
Prelude> foo Just ()
()
Just could be a nullary constructor (as in the second example), and since function application is left-associative, the compiler parses Just and x as separate arguments and you get the "different numbers of arguments" error. (And as you can see above, if there weren't the Nothing case, you'd actually get the type error for code of that form.)
The idea is that pattern syntax should mirror application syntax. If I was calling foo I couldn't write foo Just x, because that means something else (and if foo had type (Int -> Maybe Int) -> Int -> Int then it would even work). Having patterns have different rules for where parentheses are needed than expressions would be very weird.
Writing compound patterns without parentheses and trusting the compiler to automatically group things also falls apart in more complex situations. What should this mean?
foo Just x : xs = ...

Difference between where bindings, let bindings and the single assignment operator (<-)

I do not understand the difference between the three syntaxes:
where a = f (b)
do a <- f (b)
do let a = f (b)
I do understand somehow though that a <- f(b) is different from the other two, in most cases where I tried all three worked. Also I read somewhere on the net that per block you should try to get along with one let binding only in order to be "idiomatic". But I never seem to manage.
How do I decide what to use?
let foo = bar in ... simply defines foo to be the exact same thing as bar within the context of ...; you could simply use textual substitution to replace all uses of foo in ... with (bar) and get the exact same result.
where clauses are similar to let...in expressions, but go at the end of a function clause, instead of being an expression. For instance,
foo x
| p1 = ... y ...
| p2 = ... y ...
where
y = ...
There is no way to rewrite this with let...in without changing the guards into if...then...elses. Often, where clauses are used over let...in clauses purely for reasons of style.
The bind operator is something different entirely. It's used in do notation to "extract" a value from a monadic computation. That is, if foo has the type m a, then after x <- foo, x has the type a. All the other "binding" forms just define names, but <- is used for binding a computation's result to a name from within a monad. <- can only be used inside a do block, so it's exclusively used to build up a larger computation in the same monad as the action you're binding the result of.
let foo = bar in do notation is just a convenience; you can rewrite:
do let foo = bar
...
as
let foo = bar
in do ...
but that gets messy when you have a lot of such bindings, as the do blocks get nested deeper and deeper.
I don't know what the advice you mentioned is talking about; you can define multiple variables in a let...in block just fine, and
let foo = ...
bar ...
in ...
is more idiomatic than
let foo = ...
in let bar = ...
in ...

SML conversions to Haskell

A few basic questions, for converting SML code to Haskell.
1) I am used to having local embedded expressions in SML code, for example test expressions, prints, etc. which functions local tests and output when the code is loaded (evaluated).
In Haskell it seems that the only way to get results (evaluation) is to add code in a module, and then go to main in another module and add something to invoke and print results.
Is this right? in GHCi I can type expressions and see the results, but can this be automated?
Having to go to the top level main for each test evaluation seems inconvenient to me - maybe just need to shift my paradigm for laziness.
2) in SML I can do pattern matching and unification on a returned result, e.g.
val myTag(x) = somefunct(a,b,c);
and get the value of x after a match.
Can I do something similar in Haskell easily, without writing separate extraction functions?
3) How do I do a constructor with a tuple argument, i.e. uncurried.
in SML:
datatype Thing = Info of Int * Int;
but in Haskell, I tried;
data Thing = Info ( Int Int)
which fails. ("Int is applied to too many arguments in the type:A few Int Int")
The curried version works fine,
data Thing = Info Int Int
but I wanted un-curried.
Thanks.
This question is a bit unclear -- you're asking how to evaluate functions in Haskell?
If it is about inserting debug and tracing into pure code, this is typically only needed for debugging. To do this in Haskell, you can use Debug.Trace.trace, in the base package.
If you're concerned about calling functions, Haskell programs evaluate from main downwards, in dependency order. In GHCi you can, however, import modules and call any top-level function you wish.
You can return the original argument to a function, if you wish, by making it part of the function's result, e.g. with a tuple:
f x = (x, y)
where y = g a b c
Or do you mean to return either one value or another? Then using a tagged union (sum-type), such as Either:
f x = if x > 0 then Left x
else Right (g a b c)
How do I do a constructor with a tuple argument, i.e. uncurried in SML
Using the (,) constructor. E.g.
data T = T (Int, Int)
though more Haskell-like would be:
data T = T Int Bool
and those should probably be strict fields in practice:
data T = T !Int !Bool
Debug.Trace allows you to print debug messages inline. However, since these functions use unsafePerformIO, they might behave in unexpected ways compared to a call-by-value language like SML.
I think the # syntax is what you're looking for here:
data MyTag = MyTag Int Bool String
someFunct :: MyTag -> (MyTag, Int, Bool, String)
someFunct x#(MyTag a b c) = (x, a, b, c) -- x is bound to the entire argument
In Haskell, tuple types are separated by commas, e.g., (t1, t2), so what you want is:
data Thing = Info (Int, Int)
Reading the other answers, I think I can provide a few more example and one recommendation.
data ThreeConstructors = MyTag Int | YourTag (String,Double) | HerTag [Bool]
someFunct :: Char -> Char -> Char -> ThreeConstructors
MyTag x = someFunct 'a' 'b' 'c'
This is like the "let MyTag x = someFunct a b c" examples, but it is a the top level of the module.
As you have noticed, Haskell's top level can defined commands but there is no way to automatically run any code merely because your module has been imported by another module. This is entirely different from Scheme or SML. In Scheme the file is interpreted as being executed form-by-form, but Haskell's top level is only declarations. Thus Libraries cannot do normal things like run initialization code when loaded, they have to provide a "pleaseRunMe :: IO ()" kind of command to do any initialization.
As you point out this means running all the tests requires some boilerplate code to list them all. You can look under hackage's Testing group for libraries to help, such as test-framework-th.
For #2, yes, Haskell's pattern matching does the same thing. Both let and where do pattern matching. You can do
let MyTag x = someFunct a b c
in ...
or
...
where MyTag x = someFunct a b c

Resources