Related
I am looking to implement a "general" ordinal type that supports multiple "infinities" (e.g. [1,2,..., W, W+1, W+2, .. , 2 W, .., WW, etc]). I was thinking of implementing as a composite number (e.g. [5:4:2578] < [1:5:4:2578] < [1:5:4:2579] < [1:5:5:2]) with Ints, where comparison starts from the end of the list.
Currently i have implemented it as:
newtype Ordinal = Order [Int]
deriving (Eq)
instance Ord Ordinal where
(<=) x#(Order xl) y#(Order yl)
| null xl && null yl = x == y
| null xl = (Order [0]) <= y
| null yl = x <= (Order [0])
| last xl /= last yl = last xl <= last yl
| otherwise = (init xl) <= (init yl)
I feel like my code is not clean / elegant enough. Is there a standardized library / datatype that already does this? Can i refactor my code more?
Fundamentally, you have a logical error as pointed out by #4castle. In short, you should only be comparing most significant digits if they are of the same significance. For instance, [1,2] is clearly greater than [3] even though the last element of [3] is greater than the last element of [1,2] because the 2 is of greater significance than the 3. You may find that length is useful here.
One elegant strategy is to do a preliminary check for whether one of your Ordinals is clearly bigger than the other (that is, has digits with higher significance, or is "structurally bigger"), and only continue with the recursive underlying numerical check if not. As such, consider defining the recursive part as a helper function; and since it's a helper function anyway, you can call it with the reverse of the ordinal lists, allowing you to do simple pattern matching on the lists, comparing the most significant digit first, without needing "ugly" functions like last and init.
For who cares, i settled on the following implementation (helped by the Haskell reddit, in particular the user xplaticus):
compare x#(Order xl) y#(Order yl) = compare (length xl',xl') (length yl',yl')
where
xl' = dropWhile (0==) xl
yl' = dropWhile (0==) yl
His explanation was similar to DDub's thus i gave DDub the solved check here.
I have the following function, which counts number of differences between two strings:
distance1 :: String -> String -> Int
distance1 list1 list2 = length . filter (uncurry (/=)) $ zip list1 list2
It works just fine. Can work on any size lists within constant space.
I also was playing around with - let's say - low level, recursion-based, not-good implementation for this function and had the following:
distance2 :: String -> String -> Int
distance2 list1 list2 = distanceHelper 0 0
where
distanceHelper index result
| index == length list1 = result
| otherwise = distanceHelper (index + 1) (result + diff)
where
char1 = list1 !! index
char2 = list2 !! index
diff = if char1 /= char2 then 1 else 0
I know accessing by index for linked list is terrible, but here I'm not worrying about time, but about space. Since it is tail recursive, I expect it also to run for any size list within constant space.
The following is the program used to test:
main :: IO ()
main = print $ distance2 list1 list2
where
list1 = replicate count 'A'
list2 = replicate count 'B'
count = 100000000
If I'll run the one with distance1 and for any size (e.g. 100000000000000000), yes, it will be running for a very long time, but it will eat about 3-4 MB and do the job anyway.
If I'll run test with distance2 (just with 100000000), it will immediately eat a lot of memory (about 1G), but then will stop eating memory and continue to do the job without consuming more memory. So it makes impression it also runs for constant space, but that space is too much.
I would like to understand why exactly the second version takes so much memory?
Note: just in case tried second version with bang patterns, i.e. declared inner function as distanceHelper !index !result, but that didn't help.
I know accessing by index for linked list is terrible, but here I'm not worrying about time, but about space. Since it is tail recursive, I expect it also to run for any size list within constant space.
No, that's precisely the issue here.
If a list is generated with replicate count 'A', it can be generated lazily. If we access the first element, discard it, then the second one, discard it, and so on, the computation can be performed in constant space, since elements can be garbage collected quickly after they are discarded. This requires the consumer to be something like
consume [] = ...
consume (x:xs) = .... (consume xs) -- x was used and then discarded
If we instead use !! to access the list, the compiler can no longer discard the list elements. After all, we could later on request with !! an element we used a long time ago. Hence, the full list of count elements must be stored in memory.
Now, a very smart compiler might perform a static analysis and prove that the indices used in !! are strictly increasing, and we can indeed discard/garbage collect the prefix of the list. Most compilers are not that smart, though.
Further, length is also used here:
distanceHelper index result
| index == length list1 = result
...
length list1 will work in constant space if it can consume list1, i.e. if list1 is no longer used afterwards. This is not the case, so that will force the full list to be generated and kept in memory, using count cells. Yet another reason why we should avoid length and !!.
To stress the point above:
let list = replicate count 'A'
in length list
should be constant space, while
let list = replicate count 'A'
in length list + length list
can not be (barring very smart optimizations), since we can not consume list for the first length call -- we need it for the second call later on.
Even more subtly,
let list () = replicate count 'A'
in length (list ()) + length (list ())
will work in constant space, since the result of function calls is not cached. Above, we generate (and consume) the list twice, and this can be done in constant space.
Consider this simple "benchmark":
n :: Int
n = 1000
main = do
print $ length [(a,b,c) | a<-[1..n],b<-[1..n],c<-[1..n],a^2+b^2==c^2]
and appropriate C version:
#include <stdio.h>
int main(void)
{
int a,b,c, N=1000;
int cnt = 0;
for (a=1;a<=N;a++)
for (b=1;b<=N;b++)
for (c=1;c<=N;c++)
if (a*a+b*b==c*c) cnt++;
printf("%d\n", cnt);
}
Compilation:
Haskell version is compiled as: ghc -O2 triangle.hs (ghc 7.4.1)
C version is compiled as: gcc -O2 -o triangle-c triangle.c (gcc 4.6.3)
Run times:
Haskell: 4.308s real
C: 1.145s real
Is it OK behavior even for such a simple and maybe well optimizable program that Haskell is almost 4 times slower? Where does Haskell waste time?
The Haskell version is wasting time allocating boxed integers and tuples.
You can verify this by for example running the haskell program with the flags +RTS -s. For me the outputted statistics include:
80,371,600 bytes allocated in the heap
A straightforward encoding of the C version is faster since the compiler can use unboxed integers and skip allocating tuples:
n :: Int
n = 1000
main = do
print $ f n
f :: Int -> Int
f max = go 0 1 1 1
where go cnt a b c
| a > max = cnt
| b > max = go cnt (a+1) 1 1
| c > max = go cnt a (b+1) 1
| a^2+b^2==c^2 = go (cnt+1) a b (c+1)
| otherwise = go cnt a b (c+1)
See:
51,728 bytes allocated in the heap
The running time of this version is 1.920s vs. 1.212s for the C version.
I don't know how much your "bench" is relevant.
I agree that the list-comprehension syntax is "nice" to use, but if you want to compare the performances of the two languages, you should maybe compare them on a fairer test.
I mean, creating a list of possibly a lot of elements and then calculating it's length is nothing like incrementing a counter in a (triple loop).
So maybe haskell has some nice optimizations which detects what you are doing and never creates the list, but I wouldn't code relying on that, and you probably shouldn't either.
I don't think you would code your program like that if you needed to count rapidly, so why do it for this bench?
Haskell can be optimized quite well — but you need the proper techniques, and you need to know what you're doing.
This list comprehension syntax is elegant, yet wasteful. You should read the appropriate chapter of RealWorldHaskell in order to find out more about your profiling opportunities. In this exact case, you create a lot of list spines and boxed Ints for no good reason at all. See here:
You should definitely do something about that. EDIT: #opqdonut just posted a good answer on how to make this faster.
Just remember next time to profile your application before comparing any benchmarks. Haskell makes it easy to write idiomatic code, but it also hides a lot of complexity.
I want to know what is call-by-need.
Though I searched in wikipedia and found it here: http://en.wikipedia.org/wiki/Evaluation_strategy,
but could not understand properly.
If anyone can explain with an example and point out the difference with call-by-value, it would be a great help.
Suppose we have the function
square(x) = x * x
and we want to evaluate square(1+2).
In call-by-value, we do
square(1+2)
square(3)
3*3
9
In call-by-name, we do
square(1+2)
(1+2)*(1+2)
3*(1+2)
3*3
9
Notice that since we use the argument twice, we evaluate it twice. That would be wasteful if the argument evaluation took a long time. That's the issue that call-by-need fixes.
In call-by-need, we do something like the following:
square(1+2)
let x = 1+2 in x*x
let x = 3 in x*x
3*3
9
In step 2, instead of copying the argument (like in call-by-name), we give it a name. Then in step 3, when we notice that we need the value of x, we evaluate the expression for x. Only then do we substitute.
BTW, if the argument expression produced something more complicated, like a closure, there might be more shuffling of lets around to eliminate the possibility of copying. The formal rules are somewhat complicated to write down.
Notice that we "need" values for the arguments to primitive operations like + and *, but for other functions we take the "name, wait, and see" approach. We would say that the primitive arithmetic operations are "strict". It depends on the language, but usually most primitive operations are strict.
Notice also that "evaluation" still means to reduce to a value. A function call always returns a value, not an expression. (One of the other answers got this wrong.) OTOH, lazy languages usually have lazy data constructors, which can have components that are evaluated on-need, ie, when extracted. That's how you can have an "infinite" list---the value you return is a lazy data structure. But call-by-need vs call-by-value is a separate issue from lazy vs strict data structures. Scheme has lazy data constructors (streams), although since Scheme is call-by-value, the constructors are syntactic forms, not ordinary functions. And Haskell is call-by-name, but it has ways of defining strict data types.
If it helps to think about implementations, then one implementation of call-by-name is to wrap every argument in a thunk; when the argument is needed, you call the thunk and use the value. One implementation of call-by-need is similar, but the thunk is memoizing; it only runs the computation once, then it saves it and just returns the saved answer after that.
Imagine a function:
fun add(a, b) {
return a + b
}
And then we call it:
add(3 * 2, 4 / 2)
In a call-by-name language this will be evaluated so:
a = 3 * 2 = 6
b = 4 / 2 = 2
return a + b = 6 + 2 = 8
The function will return the value 8.
In a call-by-need (also called a lazy language) this is evaluated like so:
a = 3 * 2
b = 4 / 2
return a + b = 3 * 2 + 4 / 2
The function will return the expression 3 * 2 + 4 / 2. So far almost no computational resources have been spent. The whole expression will be computed only if its value is needed - say we wanted to print the result.
Why is this useful? Two reasons. First if you accidentally include dead code it doesn't weigh your program down and thus can be a lot more efficient. Second it allows to do very cool things like efficiently calculating with infinite lists:
fun takeFirstThree(list) {
return [list[0], list[1], list[2]]
}
takeFirstThree([0 ... infinity])
A call-by-name language would hang there trying to create a list from 0 to infinity. A lazy language will simply return [0,1,2].
A simple, yet illustrative example:
function choose(cond, arg1, arg2) {
if (cond)
do_something(arg1);
else
do_something(arg2);
}
choose(true, 7*0, 7/0);
Now lets say we're using the eager evaluation strategy, then it would calculate both 7*0 and 7/0 eagerly. If it is a lazy evaluated strategy (call-by-need), then it would just send the expressions 7*0 and 7/0 through to the function without evaluating them.
The difference? you would expect to execute do_something(0) because the first argument gets used, although it actually depends on the evaluation strategy:
If the language evaluates eagerly, then it will, as stated, evaluate 7*0 and 7/0 first, and what's 7/0? Divide-by-zero error.
But if the evaluation strategy is lazy, it will see that it doesn't need to calculate the division, it will call do_something(0) as we were expecting, with no errors.
In this example, the lazy evaluation strategy can save the execution from producing errors. In a similar manner, it can save the execution from performing unnecessary evaluation that it won't use (the same way it didn't use 7/0 here).
Here's a concrete example for a bunch of different evaluation strategies written in C. I'll specifically go over the difference between call-by-name, call-by-value, and call-by-need, which is kind of a combination of the previous two, as suggested by Ryan's answer.
#include<stdio.h>
int x = 1;
int y[3]= {1, 2, 3};
int i = 0;
int k = 0;
int j = 0;
int foo(int a, int b, int c) {
i = i + 1;
// 2 for call-by-name
// 1 for call-by-value, call-by-value-result, and call-by-reference
// unsure what call-by-need will do here; will likely be 2, but could have evaluated earlier than needed
printf("a is %i\n", a);
b = 2;
// 1 for call-by-value and call-by-value-result
// 2 for call-by-reference, call-by-need, and call-by-name
printf("x is %i\n", x);
// this triggers multiple increments of k for call-by-name
j = c + c;
// we don't actually care what j is, we just don't want it to be optimized out by the compiler
printf("j is %i\n", j);
// 2 for call-by-name
// 1 for call-by-need, call-by-value, call-by-value-result, and call-by-reference
printf("k is %i\n", k);
}
int main() {
int ans = foo(y[i], x, k++);
// 2 for call-by-value-result, call-by-name, call-by-reference, and call-by-need
// 1 for call-by-value
printf("x is %i\n", x);
return 0;
}
The part we're most interested in is the fact that foo is called with k++ as the actual parameter for the formal parameter c.
Note that how the ++ postfix operator works is that k++ returns k at first, and then increments k by 1. That is, the result of k++ is just k. (But, then after that result is returned, k will be incremented by 1.)
We can ignore all of the code inside foo up until the line j = c + c (the second section).
Here's what happens for this line under call-by-value:
When the function is first called, before it encounters the line j = c + c, because we're doing call-by-value, c will have the value of evaluating k++. Since evaluating k++ returns k, and k is 0 (from the top of the program), c will be 0. However, we did evaluate k++ once, which will set k to 1.
The line becomes j = 0 + 0, which behaves exactly like how you'd expect, by setting j to 0 and leaving c at 0.
Then, when we run printf("k is %i\n", k); we get that k is 1, because we evaluated k++ once.
Here's what happens for the line under call-by-name:
Since the line contains c and we're using call-by-name, we replace the text c with the text of the actual argument, k++. Thus, the line becomes j = (k++) + (k++).
We then run j = (k++) + (k++). One of the (k++)s will be evaluated first, returning 0 and setting k to 1. Then, the second (k++) will be evaluated, returning 1 (because k was set to 1 by the first evaluation of k++), and setting k to 2. Thus, we end up with j = 0 + 1 and k set to 2.
Then, when we run printf("k is %i\n", k);, we get that k is 2 because we evaluated k++ twice.
Finally, here's what happens for the line under call-by-need:
When we encounter j = c + c; we recognize that this is the first time the parameter c is evaluated. Thus we need to evaluate its actual argument (once) and store that value to be the evaluation of c. Thus, we evaluate the actual argument k++, which will return k, which is 0, and therefore the evaluation of c will be 0. Then, since we evaluated k++, k will be set to 1. We then use this stored evaluation as the evaluation for the second c. That is, unlike call-by-name, we do not re-evaluate k++. Instead, we reuse the previously evaluated initial value for c, which is 0. Thus, we get j = 0 + 0; just as if c was pass-by-value. And, since we only evaluated k++ once, k is 1.
As explained in the previous step, j = c + c is j = 0 + 0 under call-by-need, and it runs exactly as you'd expect.
When we run printf("k is %i\n", k);, we get that k is 1 because we only evaluated k++ once.
Hopefully this helps to differentiate how call-by-value, call-by-name, and call-by-need work. If it would be helpful to differentiate call-by-value and call-by-need more clearly, let me know in a comment and I'll explain the code earlier on in foo and why it works the way it does.
I think this line from Wikipedia sums things up nicely:
Call by need is a memoized variant of call by name, where, if the function argument is evaluated, that value is stored for subsequent use. If the argument is pure (i.e., free of side effects), this produces the same results as call by name, saving the cost of recomputing the argument.
Is there a programming language that supports chained notation a < b < c to be used instead of a < b and b < c in conditional statements?
Example:
if ( 2 < x < 5 )
if ( 2 < x && x < 5 )
First statementlooks better to me, it's easier to understand and the compiler could use transitivity property to warn about mistakes (e.g. 5 < x < 2 would give a warning).
Python does that.
Icon does this, and it is not part of any hacky special-case "chaining"; it is part of Icon's goal-directed evaluation model. Any comparison either succeeds or fails. If it succeeds, it produces the right-hand side. So you can write
if 0 <= i <= j < n then ...
and it works exactly the way you would expect. But it works not just for comparisons but for any expression; this means you can write your own functions that "chain" in exactly the same way. I love this aspect of Icon and wish more languages could incorporate goal-directed evaluation.
N.B. In Guido's paper introducing Python at VHLL (middle 1990s) he mentions Icon explicitly as a source of inspiration in the design of Python.
This sounds like a simple request (and clearly it is simple enough that python implemented it) but it is not necessarily that easy to use. It actually opens up the ability for a lot of errors to be caused.
Specifically, any time that you use functions (or properties in the case of C#, Getters for Java)
So
public int GetX()
{
return 4;
}
(2 < GetX() < 5);
(2 < GetX() > 5);
(5 < GetX() < 2);
Seems like it would be really simple. But problems occur if GetX() has side effects.
private int val = 10;
public int GetCountdown()
{
return val--;
}
(2 < GetCountdown() < 5);
(2 < GetCountdown() > 5);
(5 < GetCountdown() < 2);
In this situation, is "GetCountdown()" decremented twice or just once?
Would the "chained-if-statement" ever shortcut?
Consider the last statments, which roughly evaluates (in english) to "Is 5 less than some value which is less than 2) which should be impossible, but depending on the implementation and side effects, it is possible that some function (Random.NextInt()) could pass both of those tests.
So, for that reason, it would be required that each of the items is only evaluated once, the saved into a local variable for the next comparison. But then you get into shortcutting problems.
public int GetOne()
{
return 1;
}
public int GetVar()
{
return -1;
}
(GetOne() < GetVar() < GetDBVal() < GetUserInput())
Generally, you would want to first check constants and variables before doing a database hit. But if we said (as we said earlier) that all the values must be saved into local variables ahead of time, this means that it might be calling a database hit, and asking the user for information even though "GetVar()" is -1, and so the first comparison fails)
As I said earlier, clearly Python allows this syntax, so it is clearly possible. But, regardless of the technical implications which I have laid out (all of which are easy to design around) it means that your code is less clear because the next person who reads it does not know whether or not you have considered all of this. Whereas, if(x > 2 && x < 5) { } seems clear to me, I know what it does, and I know what the coder intends.