with
data ListType = List Int Int Int deriving(Show)
[1, 2, 3] and List 1 2 3, can both get a list which contains one to three, can I regard literal as a special form of value constructor?
Not just limits in Haskell.
can I regard literal as a special form of value constructor?
Basically, yes. Do note, however, that your ListType is not a list; it is (equivalent to) a tuple. Values of a list type may hold any number of elements, while ListType values can hold only three. Back to your question, though: [1, 2, 3] is indeed syntax sugar for 1 : 2 : 3 : [], in which the (:) and [] constructors appear explicitly. Weren't it for the sugar and other syntactical details, a definition for the list type might be:
data [] a = [] | (:) a ([] a)
I don't know what you mean by "literal", but the List data type that you defined above is actually not a conventional Haskell list. For one, your "List" has a fixed number of elements (3), while a Haskell list can contain from zero to an infinite number of elements. Your type is also specialized to the type Int, while Haskell lists can contain any type of elements, as long as all elements are of the same type. And, besides, Haskell lists are instances of a number of typeclasses (Functors, Monoids, Monads, etc.).
Haskell lists are a recursive data type and a possible constructor for them would be:
data List a = Empty | Cons a (List a) deriving Show
You could use this constructor as:
Cons 1 (Cons 2 (Cons 3 Empty))
Of course, it would be far more practical to use the built-in data type and build your list as:
[1,2,3]
Also, what do you really mean by "limits in Haskell"?
Haskell allows a custom syntax for lists, such as
[1,2,3]
this is just a syntactic shortcut for
1 : 2 : 3 : []
which is another syntactic shortcut for
(:) 1 ((:) 2 ((:) 3 []))
Above, (:) and [] are data constructors.
(:) :: a -> [a] -> [a]
[] :: [a]
Keep in mind that the special syntax applies only to standard lists, not to user defined types. You can get something vaguely similar with e.g.
data MyList a = Nil | a :+ MyList a
and then using the :+ value constructor in an infix way:
1 :+ 2 :+ 3 :+ Nil
Still, no [1,2,3] syntax for this type.
Related
This expression appears to be invalid because the first two elements are lists while the last element is a list of list.
[1,2,3]:[4,5]:[[]]
But in fact, it does evaluate and is equal to:
[[1,2,3],[4,5],[]]
How come?
Consider: the following appears to be invalid because the first three elements are ints, while the last is a list:
1 : 2 : 3 : []
But in fact, it does evaluate!
[1, 2, 3]
Or, more directly, and with the same result:
1 : 2 : [3]
[1,2,3]:[4,5]:[[]] is just [1,2,3] : [4,5] : [] : []
If you try
:t [[]]
in GHCI
it give
[[a]]
And [1,2,3], [4,5] is [Int],
and so Haskell infer the type of [[a]] is [[Int]]
therefore, [Int]:[Int]:[[Int]] = [[Int]]
corresponding, [1,2,3]:[4,5]:[[]] = [[1,2,3],[4,5],[]]
This is because : does not separate elements, it is the constructor to prepend an item onto a list (known as cons in lisp tradition).
Prelude> :i (:)
data [] a = ... | a : [a] -- Defined in ‘GHC.Types’
infixr 5 :
Prelude> :t (:)
(:) :: a -> [a] -> [a]
So the value on the right is already the list type that : returns. In this case, those are both [[Int]], and there just happens to be an empty list as the last element in the outer list. Because : is right associative, [1,2,3]:[4,5]:[[]] is equivalent with [1,2,3]:([4,5]:[[]]) or [[1,2,3], [4,5], []].
The prelude list type has two constructors, [] (empty list) and : (the prepend constructor). The [a,b,c] form is syntactic sugar, as specified in the Translation box in Haskell 2010 Languare Report sections 3.7, Lists.
[e1, …, ek] = e1 : (e2 : ( … (ek : [])))
I'm very new to Haskell, and I decided to learn it some days ago, thanks to the haskell wikibook.
I'm reading at this moment the matching pattern for lists, but I can't understand the syntax for list.
Here's an example (from the wikibook) :
doubleList :: [Integer] -> [Integer]
doubleList [] = []
doubleList (n:ns) = (2 * n) : doubleList ns
I don't understand the part (n:ns). How should I read it ?
You can read it like this: (head:tail), so if you have [1, 2, 3] and you match it with (x:xs), then x will be bound to the first element in the list, 1, and xs will be bound to the rest of the list, in this case [2, 3].
(:) is an operator with type a->[a]->[a]. This means that it takes an item, and a list of those items, and returns another list of the same items. The output list is formed by prepending the input item to the input list.
Here is how you can use it
1:[2,3]
will return
[1,2,3]
Because the (:) appears on the left hand side of the definition, in your case, you are pattern matching, and the operator is being used to deconstruct the value, rather than build it.
For example, if we have
func (first:rest) = ....
and call it like this
func [1,2,3]
the following values would be assigned
first=1 --notice, this is type a
rest=[2,3] --notice, this is type [a]
Another tip that might help you understand is by looking at the definition of the list data type:
data [] a = [] | a : ([] a)
Note that Haskell makes special syntax rules just for the list type, normally [] is not a valid constructor. This definition is equivalent to
data List a = Empty | Cons a (List a)
Where
[] = Empty
(:) = Cons
You would pattern match on this as
doubleList :: List Int -> List Int
doubleList Empty = Empty
doubleList (Cons n ns) = Cons (2 * n) (doubleList ns)
If written using infix form:
doubleList (n `Cons` ns) = (2 * n) `Cons` doubleList ns
So now hopefully you can see the parallels between the two definitions. Haskell also provides the special syntax rule that
[1, 2, 3, 4] = 1:2:3:4:[]
Since the former is much easier to write and read. In fact, whenever you have a list literal like [1, 2, 3, 4] in your code, the compiler first converts it to 1:2:3:4:[] before converting your code into an executable.
How is 1:(2:(3:[])) evaluated?
What rewriting steps are taken until we arrive to [1,2,3] ?
Is it
1:(2:([3])
1:([2,3])
[1,2,3]
or something else? Is the above described way the only way? Or is there an other way?
There isn't anything for Haskell to actually evaluate here, since : is the constructor for lists. When you write something like [1, 2, 3], the compiler first de-sugars this to the form 1 : 2 : 3 : [], and this is its representation in memory. It'd be like asking what the evaluation order is for Just 1. There isn't an evaluation order, because it's already in its "most evaluated" form, also known as normal form.
For lists, normal form is elements consed together in front of an empty list. If it helps, you can think of lists defined as
data [a] = [] | a : [a]
Or alternatively
data List a = Empty | Cons a (List a)
When you do pattern matching like
f (x:xs) = ...
This is equivalent to doing pattern matching like
f (Cons x xs) = ...
The only real difference is the names used.
So I guess the answer to your question is that you have the evaluation backwards, you don't go from 1:2:3:[] to [1, 2, 3], you go from [1, 2, 3] to 1:2:3:[], although this step occurs during de-sugaring. As for list comprehensions, these get de-sugared into maps and filters using monadic functions like >> and >>=. When you see something like [1..10], this actually uses the Enum instance for its elements and gets de-sugared to fromEnumTo and similar functions. All of these functions work with lists on the level of : and [], so they're just working with the list type's constructors just as it would with any other data type.
As proof, if I had the code
module Foo where
x :: [Int]
x = [1, 2, 3]
And I compiled it with ghc -c Foo.hs -ddump-ds, I'd get
Foo.x :: [GHC.Types.Int]
[LclIdX]
Foo.x =
GHC.Types.:
# GHC.Types.Int
(GHC.Types.I# 1)
(GHC.Types.:
# GHC.Types.Int
(GHC.Types.I# 2)
(GHC.Types.:
# GHC.Types.Int (GHC.Types.I# 3) (GHC.Types.[] # GHC.Types.Int)))
Which is has quite a lot of extra meta-data in there, so let's remove all the extra type annotations, module names, and other noise:
Foo.x :: [Int]
Foo.x = GHC.Types.: 1 (GHC.Types.: 2 (GHC.Types.: 3 []))
Or even more removed
x :: [Int]
x = : 1 (: 2 (: 3 []))
Note that in core (what GHC compiles Haskell source to, one of the 3 intermediate language used), we don't need parens around operators in prefix form. But it's pretty easy to see that once everything is de-sugared it's simply represented as a list consed together.
But wait! I thought you said that the parens weren't needed? That was true when it was in infix form, but now the : is being applied as a prefix function. It's pretty easy to see that with prefix, the parens are needed, especially if you replace : with Cons and [] with Empty:
x = Cons 1 (Cons 2 (Cons 3 Empty))
Since the following wouldn't type-check. It makes it look like Cons takes 6 arguments!
x = Cons 1 Cons 2 Cons 3 Empty
This question already has answers here:
What does the : infix operator do in Haskell?
(4 answers)
Closed 8 years ago.
I've tried looking it up in hoogle and other various haskell dictionaries, but I can't find it. I was under the impression that it prepends, but I'm starting to see it in ways I haven't before and I've started second guessing myself.
For example, this is one of the questions that I don't understand:
(3 points) Fill in the blank with a pattern such that fun1 [(5,6),(7,8)] returns
5 and fun1 [(10,20),(30,40),(50,60)] returns 10:
and the answer is apparently:
((y,_):_)
fun1 _____________ = y
But I am so confused by this. I understand that the underscores mean that you don't really care about what the types of those are, but I don't understand what the (:) does in this answer.
While the other answers correctly explain what : is they don't quite answer the question - in the answer you have in your question : isn't used as a function, but as a constructor to pattern match on. fun (x:xs) = x means "if the argument is of the format (x:xs) give me the x". Pattern matching is used to "pull apart" complex types based on their constructors in Haskell.
In particular, since : is a list constructor you can pull apart lists with :
(conceptually list is defined as data [] a = [] | (:) a [a], although you're not gonna get this to compile because it's builtin syntax).
A non list example: We could define a datatype data F a b = A a | B b. This would create a type F that's parameterized with two types a and b and two constructors A and B with the types a -> F a b and b -> F a b respectively.
You could then write functions that use pattern matching to get at the contained values, like
isA (A _) = True -- this value was constructed with A, so it is an A
isA (B _) = False -- this value was constructed with B so it is not an A
or
getA (A a) = a -- this value was constructed with A so we can get an a out of it
getA (B _) = undefined -- ohps! We can't get an a back here cause we don't have one!
It is a List constructor function. It is used for prepending any value in front of the list.
ghci> 2 : [3,4]
[2,3,4]
It is just another Haskell function. You can also see it's type in ghci:
ghci> :t (:)
(:) :: a -> [a] -> [a]
Regarding your question, the answer is like this ((y,_):_) because it is being used in pattern matching. The first _ is the second element of the pair and the second _ pattern matches a list.
This may help you:
ghci> (5,6):[(7,8)]
[(5,6),(7,8)]
: is the list constructor of type a -> [a] -> [a]. It is usually used infix. but you can use it as prefix if you surround it with parentheses as you did. Just like any infix operation. (E.g. (+) 4 5 == 4 + 5)
So (:) a as is the same as a:as
Every constructor in Haskell can be also used do deconstruct a value of the type if constructs in a pattern match:
f x:xs = xs
would for example define a function that takes a non empty list and returns the tail. It would fail on an empty list because the empty list is constructed by the nullary constructor []. You could make f total by adding that second constructor to the match.
f [] = []
I guess your confusion comes from the fact that in haskell there is syntactic sugar that allows you to write lists in a more convenient way. Instead of (1:(2:(3:[]))) you can write [1,2,3] which is expanded into the former by the compiler.
In addition to the answers of what (:) function does, please, bear in mind that in the context of your question : is used as a deconstructor.
It is better to view (:) as a constructor. Then, just like any other data constructor, it can be used to introspect the contents of the value. Examples are:
f (Just x) = x -- extracts the value wrapped into Maybe a
f (x:_) = x -- extracts the value wrapped into a list, [a]
f ((x,_):_) = x -- extracts the value wrapped into a tuple in the list of tuples
In all these cases Just, : and (,) are constructors. The same syntax can be used to construct or deconstruct the values - depending on the context of the expression. Compare:
f x = Just x -- wraps x into Maybe a
f x xs = x:xs -- wraps x into a list, [a]
f x y z = (x,y):z -- wraps x into a tuple in the list of tuples
To understand what fun1 does, let's first look at another function:
f (x:xs) = x
If you pass this function a list such as [5,12,33], it will match x to 5, and xs to [12,33]. The function just returns x, i.e. the first element. So this function is basically the same as head. Since we don't actually use the value xs, we can rewrite the function as:
f (x:_) = x
Now let's look at fun1, but a slightly modified version.
fun1 ((y,z):xs) = y
If we pass this function the list [(5,6),(7,8)], it will match (y,z) to the pair (5,6) and xs to [(7,8)]. So now y is 5, and that's the value we return. Again, since we don't use z or xs, we can write the function as:
fun1 ((y,_):_) = y
I'm reading A Gentle Introduction to Haskell (which is not so gentle) and it repeatedly uses the : operator without directly explaining what it does.
So, what exactly does it do?
: is the “prepend” operator:
x : xs
Returns a list which has x as first element, followed by all elements in xs. In other functional languages, this is usually called cons, because it “cons”tructs a list recursively by repeated application from an empty list:
1 : 2 : 3 : 4 : []
is the list [1, 2, 3, 4].
Could always check out the types in GHCi/HUGS, as the first steps in the tutorial encourage you to download GHC/HUGS.
Prelude> :t (:)
(:) :: a -> [a] -> [a]
Prelude> :t (++)
(++) :: [a] -> [a] -> [a]
From their respective types, it's quite easy to deduce their usage.
PS: http://haskell.org/hoogle/ is awesome.
The : operator in Haskell is the constructor for lists. It 'cons' whatever is before the colon onto the list specified after it.
For instance, a list of integers is made by 'consing' each number onto the empty list, e.g;
The list [1,2,3,4]
can be constructed as follows:
4 : [] (consing 4 to the empty list)
3 : [4] (consing 3 onto the list containing 4)
2 : [3,4] (consing 2 onto the list containing 3, 4)
1 : [2,3,4] (consing 1 onto the list containing 2,3,4)
giving you;
[1,2,3,4]
Written fully that's;
1 : 2 : 3 : 4 : []
It is the type constructor for lists. It is no different from any other type constructor like Just or Left, except that it is infix. Valid type constructors can either be words starting with a capital letter, or symbols starting with a colon.
So you can define infix constructors for your own data types. For example:
data MyList a = a :> MyList a
| Empty
in the above code we define a type called MyList with two constructors: the first is a weird-looking constructor :> which takes an element and another MyList a; the second is an empty constructor Empty which is equivalent to [] in Haskell's native lists.
The above is equivalent to :
data MyList a = Cons a (MyList a)
| Empty