I get paid to write C++ code. I'm pretty good at it. I understand it's normal usage syntax very well. I don't fucking know what a god damn thing means in Haskell. λ 5 + 7 12 :: Num a => a What the christ? The 12 I get. Got it. The colons? Not sure. I think it's just a dumb separator. Num is type! What the hell is a => a? I have no idea. In the top they have an example. primes = sieve[2..] where sieve (p:xs) = p : sie…
The New Haskell Homepage
101–110 of 258 posts
Re: The New Haskell Homepage
#102I get paid to write C++ code. I'm pretty good at it. I understand it's normal usage syntax very well. I don't fucking know what a god damn thing means in Haskell. λ 5 + 7 12 :: Num a => a What the christ? The 12 I get. Got it. The colons? Not sure. I think it's just a dumb separator. Num is type! What the hell is a => a? I have no idea. In the top they have an example. primes = sieve[2..] where sieve (p:xs) = p : sie…
For a declarative language like haskell, mathematics is arguably a much saner inspiration for notation than C/C++. I recommend avoiding any temptations to relate the two. When you see "return" or "class" in the code, treat it as a completely new idea.
Re: The New Haskell Homepage
#103Neat! A nitpick: I haven't used Haskell, so I'm trying to read the prime sieve example in the corner, but there's very little contrast between the background and the nonalphanumeric characters. Some brighter syntax highlighting would be a better choice against that dark background.
Also maybe pick a simpler example and not play into the stereotype that Haskell is for people who think they are smarter than everyone else.
Re: The New Haskell Homepage
#104Earlier quoted context omitted.
Could you suggest a simpler example? Finding primes is something that is taught in the first programming class in Indian high schools. I guess I've never thought of it as something hard. I looked at nodejs.org, and their first example is a web server! Python has the Fibonacci as it's second example (the first one show's numeric operations). Ruby does simple string operations on it's home page. While I think that is i…
Well, for one, it's a bad sieve algorithm. I think a neat algorithm to demonstrate laziness and Haskell clarity would be enumerating the Calkin-Wilf rationals. [0] It's quite a bit longer but demonstrates a number of neat ideas. I'll start first with a derivation which demonstrates all of the structure of the algorithm and then go through a series of mechanical transforms so that by the end I have a one-liner and a c…
Re: The New Haskell Homepage
#105I get paid to write C++ code. I'm pretty good at it. I understand it's normal usage syntax very well. I don't fucking know what a god damn thing means in Haskell. λ 5 + 7 12 :: Num a => a What the christ? The 12 I get. Got it. The colons? Not sure. I think it's just a dumb separator. Num is type! What the hell is a => a? I have no idea. In the top they have an example. primes = sieve[2..] where sieve (p:xs) = p : sie…
Some acknowledgement would go a long way-- in the first "slide" after you see that, a sentence about the output format seems appropriate.
Re: The New Haskell Homepage
#106Well, it sure looks nicer, I'll give you that. I'm more interested in the content, though. I was just trying here and there over the last week or so to learn some Haskell - people always seem to be raving about how cool it is. I found my way to the CIS 194 class link, the first one on the page, and I find that it really isn't very good for learning. I went through the first page, trying to run some of the stuff. I fi…
Re: The New Haskell Homepage
#107I get paid to write C++ code. I'm pretty good at it. I understand it's normal usage syntax very well. I don't fucking know what a god damn thing means in Haskell. λ 5 + 7 12 :: Num a => a What the christ? The 12 I get. Got it. The colons? Not sure. I think it's just a dumb separator. Num is type! What the hell is a => a? I have no idea. In the top they have an example. primes = sieve[2..] where sieve (p:xs) = p : sie…
Re: The New Haskell Homepage
#108I get paid to write C++ code. I'm pretty good at it. I understand it's normal usage syntax very well. I don't fucking know what a god damn thing means in Haskell. λ 5 + 7 12 :: Num a => a What the christ? The 12 I get. Got it. The colons? Not sure. I think it's just a dumb separator. Num is type! What the hell is a => a? I have no idea. In the top they have an example. primes = sieve[2..] where sieve (p:xs) = p : sie…
A note! Haskell has weird syntax. But it actually uses this syntax in cool ways, as opposed to some languages that have weird syntax in an effort to be different.
Let's consider the basic unit of Haskell programming -- the function!
Here is a function which returns its input:
f x = x
Notice that there are no parens or types or anything. Since functions are used so heavily, polluting them with parens would make your code look uglier than lisp.Now notice that I didn't include a type signature. In haskell, you can omit them if you want. The compiler will figure out the most general type. Think of this as C++11 `auto` keyword on steroids.
If I were to include the type signature, it would look like this:
f :: a -> a
f x = x
Let's break down those symbols.`::` just means "is of the type". So `f :: ...` is "function f is of the type..."
`a` is a type variable. Think of this like C++ templates! In C++, an equivalent function is
template
T f(T x) { return x; }
Where `T` is the same as our `a` in Haskell. In Haskell, it's common to use the first few letters of the alphabet for type variables.The `->` syntax is a bit funny, but it makes sense when you learn about function currying, which I will not explain now because it can be intimidating to some. For now, just think of the type signature as
arg1Type -> arg2Type -> ... -> argNType -> ResultType
So for our function `f` of type f :: a -> a
That means "The function f takes some argument of type `a`, and returns a value of the same type `a`"Now let's consider a more complex function.
f x = 2 * x
As you can see, this is a doubling function. It takes a value and doubles it. We can imagine that the value it takes can't be any arbitrary type, because not all types can be doubled! So it doesn't make much sense to pass in a string.In Java style, we might say that the type must implement the interface `Multipliable` or something. It turns out, Haskell has a system that is very roughly similar to Java interfaces or in C++, a class with a bunch of virtual methods.
Haskell calls these Typeclasses. So there is a typeclass that specifies that types in the typeclass must implement some basic numeric methods, such as +, -, etc. This typeclass is called `Num`.
So we can imagine, our doubling function only takes types that implement `Num`. Our type signature reads:
f :: Num a => a -> a
f x = x * 2
So everything between the :: and the => is typeclass specifications. So in this one, I just specify that type `a` must implement `Num`. Let's say I also required `a` to have the equivalent of a Java `toString` method, I would say: f :: (Show a, Num a) => a -> a
So now `a` must have a `toString` style method and must have numeric methods.Now we are ready to approach the `primes` bit.
The first foreign looking thing is [2..]. This is an infinite list from 2 to infinity. How can one have an infinite list? The answer is laziness.
Whenever I go and ask for the 10000th value, the list must extend itself to that value if it hasn't yet. So the list only grows for as much as you ask for, but in theory it will grow until you run out of memory.
The [m..n] syntax is just nice syntactic sugar because it's used so much. [1..10] == [1,2,3,4,5,6,7,8,9,10]
[1..] == [1,2,3,4,5,....infinity]
So this is what we know so far:
primes = sieve [2..]
Which means "primes is equal to the function sieve, called on an infinite list from 2 to infinity"Now you ask, well what the hell is the function `sieve`?
Haskell has a nice sugar for defining scoped functions within other functions with the `where` keyword.
Consider the doubling function. I could instead do:
f x = x * (three - one)
where
three = 3
one = 1
So it just let's you define values that get used in the function body in a convenient place. This is akin to math jargon where people say "blah blah x something blah where x is blah".So `sieve` is a scoped function (cannot be accessed from outside of `primes` that takes a list as an argument and apparently produces the primes that are in that list. How does it do it?
We see some weird syntax in the definition of `sieve`:
sieve (p:xs) = ...
What is this? It's pattern matching. Let me use fake C++ as an example. Consider the recursive factorial function: int fact(int n) {
if(n == 0) return 1;
return n * fact(n-1);
}
Now imagine if C++ let you do this instead: int fact(0) { return 1; }
int fact(int n) { return n * fact(n-1); }
That is, you make a special case function body when the argument is 0. At runtime, if the arg is 0, it uses the special case body, otherwise it falls through to the general body.So in Haskell, we could implement factorial like
fact :: Num a => a -> a
fact 0 = 1
fact n = n * fact (n-1)
Very clean and sexy! But now you say "Yeah, but I could just use an if statement or a switch..."Now we go into the funny syntax and power of that funny syntax! Not only can pattern matching match on values, but it can decompose those values. What do I mean? Again, let me use some fake C++ as an example.
Consider the C++ function
int f(pair my_pair) {
int x = my_pair.first;
int y = my_pair.second;
return x*y;
}
Ignore that there is no real reason to pull the values out into `x` and `y`. In a more complex function, I'm sure you can understand why it would be tedious to type `my_pair.first` over and over again and we would want to pull it into `x` or something.Now imagine if C++ let us do this:
int f(pair) {
return x*y;
}
That is, f takes a pair, and in the type declaration we decompose the pair into its first and second parts, assigning them to the variables `x` and `y`. In Haskell, this is trivial.Consider a direct translation of the C++:
f :: (Int, Int) -> Int
f my_pair = fst my_pair * snd my_pair
Now the idiomatic Haskell, with pattern matching decomposition: f :: (Int, Int) -> Int
f (x,y) = x*y
Slick, right?So what is `sieve (p:xs)` decomposing?
In Haskell, the default [] list is a linked list (there are random access arrays in various libraries). That means we can stick a value onto the front of the list in O(1) time. The way we stick a value onto the front of the list is with the `:` operator.
So
x = [1,2,3]
y = 0:x
`y` is now [0,1,2,3]Just like we can compose lists with the `:` operator, we can decompose them via pattern matching with it.
So consider the function (I'll omit the type signature for brevity)
f (p:xs) = print (p, xs)
Let's say we give `f` the argument [1,2,3,4]. What call to `:` would we have to make to get this list? [1,2,3,4] == 1:[2,3,4]
So when we send [1,2,3,4] into `f`, it gets decomposed into ` 1:[2,3,4] ` where 1 gets put into `p` and [2,3,4] gets put into `xs`.This is a very common idiom in Haskell. Let's say I wanted to make a function that added 1 to every value in a list. Ignoring that there are much cooler/efficient ways to do this in Haskell, let's make a specialized function for it.
addOne (x:xs) = x+1 : addOne xs
So let's read through that. In our pattern matching decomposition, we pull off the first value of the list and store it in `x`, and we take the rest of the list and store it in `xs`.Now in our function body, we recompose a list with different values. Those values are `x+1` for the first value, and `addOne xs` for the second value. So we add one to the first value, and stick it into the front of the rest of the list after the rest has had 1 added to its values. You might notice now, that there is no bottom-out case for this recursion. So let's add one.
addOne [] = []
addOne (x:xs) = x+1 : addOne xs
So we pattern match to catch the special case of the empty list, which returns the empty list, and then we decompose the general case as previously explained.So `sieve` is pulling off the first value, storing it in `p`, and taking the rest of the list and storing it in `xs`.
It is returning...
p : sieve [x | x
So, that is `p` stuck onto the front of... sieve [x | x
And we know that sieve returns all of the primes within its argument, so in English... p stuck onto the front of all the primes in [x | x
So now what the hell is [x | x Hackernews said my comment was too long. Read the rest here: http://pastebin.com/UesYMjjJRe: The New Haskell Homepage
#109I get paid to write C++ code. I'm pretty good at it. I understand it's normal usage syntax very well. I don't fucking know what a god damn thing means in Haskell. λ 5 + 7 12 :: Num a => a What the christ? The 12 I get. Got it. The colons? Not sure. I think it's just a dumb separator. Num is type! What the hell is a => a? I have no idea. In the top they have an example. primes = sieve[2..] where sieve (p:xs) = p : sie…
Being a god in C++ won't give you anything regarding foreign paradigms. Are you familiar with other FP languages such as ML, Miranda or even Lisp ? More than syntax it's the semantics that differs a lot. Laziness, Immutability...
Re: The New Haskell Homepage
#110I get paid to write C++ code. I'm pretty good at it. I understand it's normal usage syntax very well. I don't fucking know what a god damn thing means in Haskell. λ 5 + 7 12 :: Num a => a What the christ? The 12 I get. Got it. The colons? Not sure. I think it's just a dumb separator. Num is type! What the hell is a => a? I have no idea. In the top they have an example. primes = sieve[2..] where sieve (p:xs) = p : sie…
Ok I'll take a stab at a super high level crash course: A note! Haskell has weird syntax. But it actually uses this syntax in cool ways, as opposed to some languages that have weird syntax in an effort to be different. Let's consider the basic unit of Haskell programming -- the function! Here is a function which returns its input: f x = x Notice that there are no parens or types or anything. Since functions are used…