I mean what advantages does list has on other data structures which make it almost inevitable in functional languages?
"There is no spoon."
What if I told you there is no such thing as strings? There exists only lists of single characters.
Then what if I told you there is no such thing as a list? There exists only pairs.
; construct a pair of a and b
(cons 'a 'b) ; => ('a 'b)
; get the first element of the pair
(first (cons 'a 'b)) ; => 'a
; get the second element of the pair
(second (cons 'a 'b)) ; => 'b
; create a "list"
(define x (cons 'a (cons 'b (cons 'c (cons 'd (cons 'e null))))))
; => ('a ('b ('c ('d ('e ())))))
; get the third element in the "list", x
(first (second (second x)))
; => 'c
Now what if I told you there is no such thing as pairs? There exists only lambdas.
(define (cons x y)
(λ (f) (f x y)))
(define (first p)
(p (λ (x y) x)))
(define (second p)
(p (λ (x y) y)))
Of course this is just one possible implementation. But it's important to realize that it's all just an illusion.
Data abstraction is truly magical. Good languages allow you to invent any structure you wish to work with and define any constructors/selectors that make it useful to work with your structure. Some languages just offer more syntactic sugar than others.
Lists are common because, as programmers, we often deal with ordered collections of things. Other common types are Sets and Maps. Just don't fool yourself into thinking it's anything super special ^,^
Functional languages prefer immutability so, when it comes to data structures, functional languages prefer persistent data structures. In brief, persistent data structures are data structures where we can continue to access any previous version of the structure as well as the current version. We do not mutate the existing data structure, we simply use the existing data structure as a basis to create a new one.
This can be done for any data structure simply by copying. For instance, consider some pseudo-F#:
let array1 = [| 1, 2, 3, 4, 5 |]
let array2 = append 6 array1 // [| 1, 2, 3, 4, 5, 6 |]
To implement the append function, we'd have to create a new array of n+1 size and populate it with a copy of array1 and the element to be appended.
Note how this isn't very efficient, every append requires both n copies and allocating memory for the entire structure.
Consider instead we define some type:
type List<'a> =
|Empty
|Cons of 'a * List<'a>
Using the Cons case, we can construct new lists from an old list and a single element.
Consider we now have a list of 1 million elements:
let list1 = [1..1000000]
let list2 = Cons (0, list1) // [0..1000000]
In this case, list2 simply refers to list1, no copying is required. Hence, prepending to the start of the list is an O(1) operation and the memory footprint only grows linearly with each element despite the data persistence.
There are many other persistent data structures, Binary Trees are often used to make immutable Sets and Dictionaries. Finger Trees can be the basis of structures like Deques and Priority queues.
So, in short, lists are widely used in functional languages because they are a simple, efficient, persistent data structure.
Related
using:
data type List a = Empty | Cons a (List a)
How can one represent [[a]]? This has to have a simple solution that I'm just blind to so somebody's input would be greatly appreciated, thanks!
I was trying to use List (List a) or List (Cons x xs) but that responds with 'List' not in scope which kinda makes sense to me.
The type of a list of lists of a is indeed List (List a)). But we do not construct a value with this.
If we for example want to construct a list with a singleton list that contains 1, we can write this as:
oneList1 :: List (List Int)
oneList1 = Cons (Cons 1 Empty) Empty
The outer Cons is the cons of the outer list, as first (and only) element it has a Cons 1 Empty, this is the inner list. A Cons h t represents a list with h (here 1) the head (first element) and Empty the tail (remaining elements). So Cons 1 Empty is a singleton list with 1 as only value.
We wrap that in the outer cons Cons (Cons 1 Empty) Empty that thus specifies that the outer list is a singleton list as well. The oneList1 is thus equivalent to [[1]].
This question already has answers here:
how to populate existing list / array
(2 answers)
Closed 4 years ago.
How to append an element at the end of a list in ReasonML (the equivalent of Array.concat in JavaScript)?
While Neil's answer is technically correct, it glosses over some details that you might want to consider before reaching for append; specifically that while adding an element to the beginning of a list is very cheap, adding an element to the end is very expensive.
To understand why, let's look at how a list is defined and constructed. The (conceptual) definition of a list is:
// Reason
type list('a) = Cons('a, list('a)) | Nil;
(* OCaml *)
type 'a list = Cons of 'a* 'a list | Nil
where Nil represents the end of a list (and by itself an empty list) and Cons represents a node in the list, containing an element of type 'a and a pointer to the rest of the list (list('a), OCaml: 'a list).
If we took away all the syntax sugar and every helper function, you would have to construct a list like this:
// Reason
let myList = Cons(1, Cons(2, Cons(3, Nil)));
(* OCaml *)
let myList = Cons (1, Cons (2, Cons (3, Nil)))
To add an element to the head of this list then, we construct a node containing our new element and a pointer to the old list:
// Reason
let myBiggerList = Cons(0, myList);
(* OCaml *)
let myBiggerList = Cons (0, myList)
This is exactly the same as doing [0, ...myList] (OCaml: 0 :: myList). If myList could change we wouldn't be able to do this, of course, but we know it doesn't since lists are immutable. That makes this very cheap, and for the same reason it's just as cheap to pop the head off, which is why you'll usually see list processing functions implemented using recursion, like this:
// Reason
let rec map = f =>
fun | [] => []
| [x, ...xs] => [f(x), ...map(f, xs)];
(* OCaml *)
let rec map f = function
| [] -> []
| x::xs -> (f x) :: (map f xs)
Ok, so then why is it so expensive to add an element to the tail of the list? If you look back at myList, adding an element to the end means replacing the final Nil with, say, Cons(4, Nil). But then we need to replace Cons(3, ...) since that points to the old Nil, and Cons(2, ...) because it point to the old Cons(3, ...), and so on through the entire list. And you have to do that every time you add an element. That quickly adds up.
So what should you do instead?
If you're adding to the end and either just iterating through it or always taking elements off the end, like you often would in JavaScript, you cam most likely just reverse your logic. Instead of adding to and taking off the end, add to and take off the beginning.
If you actually need a FIFO data structure, where elements are inserted at one end and taken off at the other, consider using a Queue instead. In general, have a look at this comparison of the performance characteristics of the standard containers.
Or if this is all a bit much and you'd really just like to do it like you're used to from JavaScript, just use an array instead of a list. You'll find all the functions you're familiar with in the Js.Array module
You can use List.append or the # operator which is shorthand for List.append.
let lstA = [ 1 ];
let lstB = lstA # [ 2 ];
let lstC = List.append(lstB, [ 3 ]);
Here is the documentation for List methods: https://reasonml.github.io/api/List.html
See a playground link here: https://reasonml.github.io/en/try.html?reason=DYUwLgBMDOYIIQLwQNoQIwQLoG4BQokMYAQklLAgAKoQBM2+hFYAwuQDICWsAdAIYAHQSAB2AEwAUxEgBpaAZmwBKfEA
I want to create following list in Lisp.
((lambda(x) (cons x x)) (cons'A 'B))
creates this list, but
((lambda(x y) (cons x y)) (cons'A 'B) (cons 'A 'B))
and
(cons (cons 'A 'B) (cons 'A 'B))
do not create the list.
My challenge is why!? How does the first command create this list and the others do not? Any detail?
Every time (cons 'A 'B) is called, a fresh cons cell is created, so your second two expressions create two "similar" (equal but not eql) objects (A . B),
You want to create a cons of A and B:
(cons 'A 'B)
Then you want to refer to it twice from another cons. So if x is a reference to this existing cons, you want
(cons x x)
Wrapping up, we get
(let ((x (cons 'A 'B)) (cons x x))
or equivalently
((lambda (x) (cons x x)) (cons 'A 'B))
If you do (cons 'A 'B) twice you create two cells:
AB
AB
and the cons of those will contain one link to the first, and another to the second.
(Using a lambda to refer to them is a pointless obfuscation; the point of the example with the lambda form is that you use x twice. The form
((lambda (x y) (cons x y)) (cons 'A 'B) (cons 'A 'B))
is just a very tedious way to write
(cons (cons 'A 'B) (cons 'A 'B))
whereas in the original example there is -- pointedly -- only one instance of (cons 'A 'B) which you want to be able to refer to twice.)
The purpose of this exercise is to illustrate the difference between "surface" equivalence and identity. Two lists which contain the same values are still two different lists, whereas two references to the same list are identical. As #sde hints, this makes a difference for understanding comparisons; the prototypical example is that equal is true for distinct lists containing the same values (as well as identical lists, of course), whereas eql is only true if its arguments are in fact identical (i.e. they refer to the same object).
In The Little Schemer there is a function to check, whether the list is flat:
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (lat? (cdr l)))
(else #f))))
I'm trying to write the same recursive function in Haskell, but have no success:
is_lat :: [a] -> Bool
is_lat [] = True
is_lat ???
How do i check that the parameter is not in the form [[a]]? In other words, [1,2,3] is a valid input, but [[1,3], [2,4]] and [[[1,2,3]]] aren't.
I want to use this further in recursive functions that accept lists to make sure that i deal with flat lists only.
EDIT: I see that people are confused because of the is_lat :: [a] -> Bool type signature. I agree now, that i shouldn't check type on runtime. However, is it possible to check the type on compile-time? How can i make the function work only for flat lists? Or should i completely change my way of thinking?
You can't really think of nested lists the same way in Haskell as in Scheme, because they're not the same data structure. A Haskell list is homogenous, where as a Lisp "list" is actually closer to a rose tree (as pointed out by C.A.McCann below). As an illustrative example, take a look at how the WYAS48 parsing section defines LispVal.
If you really, really, really want to do runtime type checking, even though it's usually a bad idea and very unconventional in Haskell, look into Data.Typeable. This response might be useful too.
The real answer to this question is "You need to think about your arguments differently in Haskell than in Lisp, which results in never needing to perform this check yourself at runtime" (and I say this as a Common Lisper, so I understand how frustrating that is to start with).
Addendum: In response to your edit, Haskell's type system automatically ensures this. If you have a function of type foo :: [Int] -> Int, for example, and you pass it ["One", "Two", "Three"] or [[1, 2, 3]], you'll get a compile-time error telling you what just exploded and why. If you want to specialize a function, just declare a more specific type.
For instance (don't write code like this, it's just for illustrative purposes), say you have a simple function like
myLookup index map = lookup index map
If you load this into GHCi and run :t myLookup, it'll tell you that the functions' type is myLookup :: Eq a => a -> [(a, b)] -> Maybe b which means that it can take a key of any type that derives Eq (anything you can run == on). Now, say that for whatever reason you want to ensure that you only use numbers as keys. You'd ensure that by adding a more specific type declaration
myLookup :: Int -> [(Int, a)] -> Maybe a
myLookup index map = lookup index map
Now, even though there's nothing in the body of the function preventing it from dealing with other key types, you'll get a type error at compile time if you try to pass it something other than an Int index or something other than an [(Int, a)] map. As a result, this
myLookup :: Int -> [(Int, a)] -> Maybe a
myLookup ix lst = lookup ix lst
main :: IO ()
main = putStrLn . show $ myLookup 1 [(1, "Foo")]
will compile and run fine, but this
myLookup :: Int -> [(Int, a)] -> Maybe a
myLookup ix lst = lookup ix lst
main :: IO ()
main = putStrLn . show $ myLookup "Nope.jpg" [("Foo", 1)]
will do neither. On my machine it errors at compile time with
/home/inaimathi/test.hs:5:35:
Couldn't match expected type `Int' with actual type `[Char]'
In the first argument of `myLookup', namely `"Nope.jpg"'
In the second argument of `($)', namely
`myLookup "Nope.jpg" [("Foo", 1)]'
In the expression:
putStrLn . show $ myLookup "Nope.jpg" [("Foo", 1)]
Failed, modules loaded: none.
I really hope that didn't confuse you further.
This is both impossible and unnecessary with standard Haskell lists because Haskell is strongly typed; either all elements of a list are themselves lists (in which case the type is [a] = [[b]] for some b), or they are not.
E.g. if you try to construct a mixed list, you will get an error from the compiler:
Prelude> ["hello", ["world!"]]
<interactive>:3:12:
Couldn't match expected type `Char' with actual type `[Char]'
In the expression: "world!"
In the expression: ["world!"]
In the expression: ["hello", ["world!"]]
The function type [a] -> Bool implicitly means forall a. [a] -> Bool, in other words it's defined identically for lists of all possible element types. That does include types like [[Int]] or [[[String]]] or any depth of nesting you can think of. But it doesn't--and can't--matter to your function what the element type is.
As far as this function is concerned, the input is always a list whose elements are some opaque, unknown type. It will never receive nested lists containing that same opaque type.
Well, I guess, in Haskell you are limited to http://ideone.com/sPhRCP:
main = do -- your code goes here
print $isFlat [Node 1, Node 2, Node 3]
print $isFlat [Node 1, Node 2, Branch [Node 3, Node 4, Node 5], Node 6]
data Tree a = Node a | Branch [Tree a]
isFlat :: [Tree a] -> Bool
isFlat = all isNode where
isNode (Node _) = True
isNode _ = False
In non strictly-typed languages every object has run-time type information and thus can be polymorphic. This might be a complicated network of coercions, like in Scala (less complicated if you're in C++), or just "everything is an object, and object is everything" like in purely dynamic languages (Lisp, JS, ...).
Haskell is strictly-typed.
I trying to complete this exercise;
Write a Lisp function that takes as input a list of elements, such as (A B C)
, and returns a list in which the position of each element follows it, such as (A 1 B 2 C 3)
I'm trying to do it with two functions, however its not working correctly, I'm just getting the same list. Here is my code:
(defun insert (index var userList)
(if (or (eql userList nil) (eql index 1))
(cons var userList)
(cons (car userList) (insert (- index 1) var (cdr userList)))))
(defun insertIndex (userList)
(setq len (length userList))
(loop for x from 1 to len
do (insert x x userList)))
The insert functions seems to work fine on its own, but it seems like it doesn't do anything with loop. I'm new lisp and any help would be appreciated, thanks in advance.
Positions in Lisp start with 0. In insertIndex the variable len is not defined. The LOOP does not return any useful value.
If you want to solve it with recursion, the solution is much simpler.
You need to test for the end condition. If the list is empty, return the empty list.
Otherwise create a new list with the FIRST element, the current position and the result of calling the function on the rest of the list and the position increased by one.
(LIST* 1 2 '(3 4)) is shorter for (cons 1 (cons 2 '(3 4))).
Here is the example with a local function. To create a top-level function with DEFUN is now your task. You only need to rewrite the code a bit. LABELS introduces a potentially recursive local function.
(labels ((pos-list (list pos)
(if (null list)
'()
(list* (first list)
pos
(pos-list (rest list) (1+ pos))))))
(pos-list '(a b c d e f) 0))
The main problem with your insertIndex function is that the do clause of loop is for side-effects only, it doesn't change the return value of the loop. (And your insert is side-effect free.) The right loop clause to add elements to a list return value is collect. (There are also append and nconc to join multiple lists.)
This is a working function:
(defun insert-index (list)
(loop for elt in list and i from 1
collect elt
collect i))
Your whole expectations about the behaviour of the insert and insertIndex functions seem to be flawed. You need to get a clearer mental model about which functions are side-effecting, which are not, and whether you need side-effects or not to solve some particular problem.
Also, you shouldn't call setq on an undefined variable in Common Lisp. You need to first use let to introduce a new local variable.
Minor points: CamelCase is very unidiomatic in Lisp. The idiomatic way to seperate words in identifiers is to use dashes, like I did in my code example. And you don't need to do (eql something nil), there's the special null function to check if something's nil, e.g. (null something).