Is this Haskell Tower of Hanoi solution more efficient or simply redundant?











up vote
1
down vote

favorite
1












This Haskell solution has been described as recursive, but not quite efficient according to a few claims, so I have tried to rewrite it with that in mind. The problem is described in a course that is available online and whose homework was the Tower of Hanoi.



A new solution of mine:



type Peg = String
type Move = (Peg, Peg)

hanoi :: Integer -> Peg -> Peg -> Peg -> [Move]

hanoi n a b c = hanoiToList n a b c
where
hanoiToList 0 _ _ _ l = l
-- hanoiToList 1 a b _ l = (a, b) : l
hanoiToList n a b c l = hanoiToList (n-1) a c b ((a, b) : hanoiToList (n-1) c b a l)




Let me explain the reasoning: if the function is going to end up as a list, then you had better compare it to another that takes an empty one as an argument, otherwise append it after it has been solved, which I believe to be the cause of inefficiency, thus leading to the same function being called in its place. The result has been checked and it's correct, but I wanted to know whether this is more efficient or simply redundant, considering the previous solution that I linked to.



EDIT: I commented a line that was unnecessary.










share|improve this question




















  • 2




    This version is tail-recursive, which might make it more efficient, yeah. To know for sure, you could try benchmarking it with criterion or examining the optimised GHC Core output with -O2 -ddump-simpl (with -dsuppress-uniques -dsuppress-module-prefixes to make it more readable).
    – Jon Purdy
    Nov 8 at 1:11






  • 1




    The solution you posted is, essentially, the standard recursive solution except that it uses difference lists instead of regular ones. Difference lists admit a faster concatenation, which you exploit to gain performance.
    – chi
    Nov 8 at 10:07










  • Funny that you mention that, because it's the next homework assignment in the Haskell tutorial that I'm following, which you may be familiar with. Perhaps it's meant to tell me that, when I learn something new, I should apply it to the previous exercise to improve it. Thank you Jon Purdy for criterion too.
    – Marco_O
    Nov 8 at 11:19












  • @JonPurdy No, this is not tail-recursive. There is one recursive call in tail position (good), but there's also another one which is not in tail position. Perhaps you missed the second call.
    – chi
    Nov 8 at 12:28












  • @chi yes, syntactically it is a nested recursion, but really because of Haskell's laziness it's not a double recursion like e.g. Fibonacci (where the nested call is forced by the strict +) but a guarded recursion (for the 2nd argument) -- the call is delayed (and not because of the :, but just because of the laziness). so it is very much like tail recursive tree traversal with explicit stack of "do-next" notes (either functions, or just the previously visited tree nodes themselves). when the leaf is reached the next action is called in tail position too.
    – Will Ness
    Nov 8 at 14:48

















up vote
1
down vote

favorite
1












This Haskell solution has been described as recursive, but not quite efficient according to a few claims, so I have tried to rewrite it with that in mind. The problem is described in a course that is available online and whose homework was the Tower of Hanoi.



A new solution of mine:



type Peg = String
type Move = (Peg, Peg)

hanoi :: Integer -> Peg -> Peg -> Peg -> [Move]

hanoi n a b c = hanoiToList n a b c
where
hanoiToList 0 _ _ _ l = l
-- hanoiToList 1 a b _ l = (a, b) : l
hanoiToList n a b c l = hanoiToList (n-1) a c b ((a, b) : hanoiToList (n-1) c b a l)




Let me explain the reasoning: if the function is going to end up as a list, then you had better compare it to another that takes an empty one as an argument, otherwise append it after it has been solved, which I believe to be the cause of inefficiency, thus leading to the same function being called in its place. The result has been checked and it's correct, but I wanted to know whether this is more efficient or simply redundant, considering the previous solution that I linked to.



EDIT: I commented a line that was unnecessary.










share|improve this question




















  • 2




    This version is tail-recursive, which might make it more efficient, yeah. To know for sure, you could try benchmarking it with criterion or examining the optimised GHC Core output with -O2 -ddump-simpl (with -dsuppress-uniques -dsuppress-module-prefixes to make it more readable).
    – Jon Purdy
    Nov 8 at 1:11






  • 1




    The solution you posted is, essentially, the standard recursive solution except that it uses difference lists instead of regular ones. Difference lists admit a faster concatenation, which you exploit to gain performance.
    – chi
    Nov 8 at 10:07










  • Funny that you mention that, because it's the next homework assignment in the Haskell tutorial that I'm following, which you may be familiar with. Perhaps it's meant to tell me that, when I learn something new, I should apply it to the previous exercise to improve it. Thank you Jon Purdy for criterion too.
    – Marco_O
    Nov 8 at 11:19












  • @JonPurdy No, this is not tail-recursive. There is one recursive call in tail position (good), but there's also another one which is not in tail position. Perhaps you missed the second call.
    – chi
    Nov 8 at 12:28












  • @chi yes, syntactically it is a nested recursion, but really because of Haskell's laziness it's not a double recursion like e.g. Fibonacci (where the nested call is forced by the strict +) but a guarded recursion (for the 2nd argument) -- the call is delayed (and not because of the :, but just because of the laziness). so it is very much like tail recursive tree traversal with explicit stack of "do-next" notes (either functions, or just the previously visited tree nodes themselves). when the leaf is reached the next action is called in tail position too.
    – Will Ness
    Nov 8 at 14:48















up vote
1
down vote

favorite
1









up vote
1
down vote

favorite
1






1





This Haskell solution has been described as recursive, but not quite efficient according to a few claims, so I have tried to rewrite it with that in mind. The problem is described in a course that is available online and whose homework was the Tower of Hanoi.



A new solution of mine:



type Peg = String
type Move = (Peg, Peg)

hanoi :: Integer -> Peg -> Peg -> Peg -> [Move]

hanoi n a b c = hanoiToList n a b c
where
hanoiToList 0 _ _ _ l = l
-- hanoiToList 1 a b _ l = (a, b) : l
hanoiToList n a b c l = hanoiToList (n-1) a c b ((a, b) : hanoiToList (n-1) c b a l)




Let me explain the reasoning: if the function is going to end up as a list, then you had better compare it to another that takes an empty one as an argument, otherwise append it after it has been solved, which I believe to be the cause of inefficiency, thus leading to the same function being called in its place. The result has been checked and it's correct, but I wanted to know whether this is more efficient or simply redundant, considering the previous solution that I linked to.



EDIT: I commented a line that was unnecessary.










share|improve this question















This Haskell solution has been described as recursive, but not quite efficient according to a few claims, so I have tried to rewrite it with that in mind. The problem is described in a course that is available online and whose homework was the Tower of Hanoi.



A new solution of mine:



type Peg = String
type Move = (Peg, Peg)

hanoi :: Integer -> Peg -> Peg -> Peg -> [Move]

hanoi n a b c = hanoiToList n a b c
where
hanoiToList 0 _ _ _ l = l
-- hanoiToList 1 a b _ l = (a, b) : l
hanoiToList n a b c l = hanoiToList (n-1) a c b ((a, b) : hanoiToList (n-1) c b a l)




Let me explain the reasoning: if the function is going to end up as a list, then you had better compare it to another that takes an empty one as an argument, otherwise append it after it has been solved, which I believe to be the cause of inefficiency, thus leading to the same function being called in its place. The result has been checked and it's correct, but I wanted to know whether this is more efficient or simply redundant, considering the previous solution that I linked to.



EDIT: I commented a line that was unnecessary.







performance haskell recursion towers-of-hanoi






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 8 at 9:17

























asked Nov 8 at 0:46









Marco_O

185




185








  • 2




    This version is tail-recursive, which might make it more efficient, yeah. To know for sure, you could try benchmarking it with criterion or examining the optimised GHC Core output with -O2 -ddump-simpl (with -dsuppress-uniques -dsuppress-module-prefixes to make it more readable).
    – Jon Purdy
    Nov 8 at 1:11






  • 1




    The solution you posted is, essentially, the standard recursive solution except that it uses difference lists instead of regular ones. Difference lists admit a faster concatenation, which you exploit to gain performance.
    – chi
    Nov 8 at 10:07










  • Funny that you mention that, because it's the next homework assignment in the Haskell tutorial that I'm following, which you may be familiar with. Perhaps it's meant to tell me that, when I learn something new, I should apply it to the previous exercise to improve it. Thank you Jon Purdy for criterion too.
    – Marco_O
    Nov 8 at 11:19












  • @JonPurdy No, this is not tail-recursive. There is one recursive call in tail position (good), but there's also another one which is not in tail position. Perhaps you missed the second call.
    – chi
    Nov 8 at 12:28












  • @chi yes, syntactically it is a nested recursion, but really because of Haskell's laziness it's not a double recursion like e.g. Fibonacci (where the nested call is forced by the strict +) but a guarded recursion (for the 2nd argument) -- the call is delayed (and not because of the :, but just because of the laziness). so it is very much like tail recursive tree traversal with explicit stack of "do-next" notes (either functions, or just the previously visited tree nodes themselves). when the leaf is reached the next action is called in tail position too.
    – Will Ness
    Nov 8 at 14:48
















  • 2




    This version is tail-recursive, which might make it more efficient, yeah. To know for sure, you could try benchmarking it with criterion or examining the optimised GHC Core output with -O2 -ddump-simpl (with -dsuppress-uniques -dsuppress-module-prefixes to make it more readable).
    – Jon Purdy
    Nov 8 at 1:11






  • 1




    The solution you posted is, essentially, the standard recursive solution except that it uses difference lists instead of regular ones. Difference lists admit a faster concatenation, which you exploit to gain performance.
    – chi
    Nov 8 at 10:07










  • Funny that you mention that, because it's the next homework assignment in the Haskell tutorial that I'm following, which you may be familiar with. Perhaps it's meant to tell me that, when I learn something new, I should apply it to the previous exercise to improve it. Thank you Jon Purdy for criterion too.
    – Marco_O
    Nov 8 at 11:19












  • @JonPurdy No, this is not tail-recursive. There is one recursive call in tail position (good), but there's also another one which is not in tail position. Perhaps you missed the second call.
    – chi
    Nov 8 at 12:28












  • @chi yes, syntactically it is a nested recursion, but really because of Haskell's laziness it's not a double recursion like e.g. Fibonacci (where the nested call is forced by the strict +) but a guarded recursion (for the 2nd argument) -- the call is delayed (and not because of the :, but just because of the laziness). so it is very much like tail recursive tree traversal with explicit stack of "do-next" notes (either functions, or just the previously visited tree nodes themselves). when the leaf is reached the next action is called in tail position too.
    – Will Ness
    Nov 8 at 14:48










2




2




This version is tail-recursive, which might make it more efficient, yeah. To know for sure, you could try benchmarking it with criterion or examining the optimised GHC Core output with -O2 -ddump-simpl (with -dsuppress-uniques -dsuppress-module-prefixes to make it more readable).
– Jon Purdy
Nov 8 at 1:11




This version is tail-recursive, which might make it more efficient, yeah. To know for sure, you could try benchmarking it with criterion or examining the optimised GHC Core output with -O2 -ddump-simpl (with -dsuppress-uniques -dsuppress-module-prefixes to make it more readable).
– Jon Purdy
Nov 8 at 1:11




1




1




The solution you posted is, essentially, the standard recursive solution except that it uses difference lists instead of regular ones. Difference lists admit a faster concatenation, which you exploit to gain performance.
– chi
Nov 8 at 10:07




The solution you posted is, essentially, the standard recursive solution except that it uses difference lists instead of regular ones. Difference lists admit a faster concatenation, which you exploit to gain performance.
– chi
Nov 8 at 10:07












Funny that you mention that, because it's the next homework assignment in the Haskell tutorial that I'm following, which you may be familiar with. Perhaps it's meant to tell me that, when I learn something new, I should apply it to the previous exercise to improve it. Thank you Jon Purdy for criterion too.
– Marco_O
Nov 8 at 11:19






Funny that you mention that, because it's the next homework assignment in the Haskell tutorial that I'm following, which you may be familiar with. Perhaps it's meant to tell me that, when I learn something new, I should apply it to the previous exercise to improve it. Thank you Jon Purdy for criterion too.
– Marco_O
Nov 8 at 11:19














@JonPurdy No, this is not tail-recursive. There is one recursive call in tail position (good), but there's also another one which is not in tail position. Perhaps you missed the second call.
– chi
Nov 8 at 12:28






@JonPurdy No, this is not tail-recursive. There is one recursive call in tail position (good), but there's also another one which is not in tail position. Perhaps you missed the second call.
– chi
Nov 8 at 12:28














@chi yes, syntactically it is a nested recursion, but really because of Haskell's laziness it's not a double recursion like e.g. Fibonacci (where the nested call is forced by the strict +) but a guarded recursion (for the 2nd argument) -- the call is delayed (and not because of the :, but just because of the laziness). so it is very much like tail recursive tree traversal with explicit stack of "do-next" notes (either functions, or just the previously visited tree nodes themselves). when the leaf is reached the next action is called in tail position too.
– Will Ness
Nov 8 at 14:48






@chi yes, syntactically it is a nested recursion, but really because of Haskell's laziness it's not a double recursion like e.g. Fibonacci (where the nested call is forced by the strict +) but a guarded recursion (for the 2nd argument) -- the call is delayed (and not because of the :, but just because of the laziness). so it is very much like tail recursive tree traversal with explicit stack of "do-next" notes (either functions, or just the previously visited tree nodes themselves). when the leaf is reached the next action is called in tail position too.
– Will Ness
Nov 8 at 14:48














1 Answer
1






active

oldest

votes

















up vote
3
down vote













Yep, that gets rid of the inefficient copying of (:) constructors. It's a slightly non-idiomatic way to write it, but the more idiomatic way should have identical performance when compiled with optimizations.



hanoi n a b c = hanoiToList n a b c 
where
hanoiToList 0 _ _ _ = id
hanoiToList n a b c = hanoiToList (n-1) a c b . ((a, b) :) . hanoiToList (n-1) c b a


That's the slightly more idiomatic approach. It's all about emphasizing the viewpoint that you're building up a transformation of a value. In practice it's identical as long as function composition is being inlined and simplified as expected.






share|improve this answer























  • Strange, I thought that, since you had an empty list as an argument of "hanoiToList", you had to put something in its place ('l' in my case), so that it matched. Is this correct?
    – Marco_O
    Nov 8 at 1:26










  • @Marco_O nah. Functions are values that can be returned from other functions. If you never inspect an argument, it's often possible to never even name it.
    – Carl
    Nov 8 at 2:33










  • Thank you! I noticed something that was off about my code. I'm going to edit it to show you the changes.
    – Marco_O
    Nov 8 at 9:16












  • @Marco_O Ah, yes. Made the same edit to my answer.
    – Carl
    Nov 8 at 12:51






  • 1




    @Marco_O hanoiToList 0 _ _ _ l = l === hanoiToList 0 _ _ _ = l -> l === hanoiToList 0 _ _ _ = id. it's the same thing. So even if you have hanoiToList n a b c as your top call, what's being matched in the definition is hanoiToList n a b c, which is evaluated, returns a function, and that function gets applied to . looks different, but is the same.
    – Will Ness
    Nov 8 at 15:21













Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53200042%2fis-this-haskell-tower-of-hanoi-solution-more-efficient-or-simply-redundant%23new-answer', 'question_page');
}
);

Post as a guest
































1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
3
down vote













Yep, that gets rid of the inefficient copying of (:) constructors. It's a slightly non-idiomatic way to write it, but the more idiomatic way should have identical performance when compiled with optimizations.



hanoi n a b c = hanoiToList n a b c 
where
hanoiToList 0 _ _ _ = id
hanoiToList n a b c = hanoiToList (n-1) a c b . ((a, b) :) . hanoiToList (n-1) c b a


That's the slightly more idiomatic approach. It's all about emphasizing the viewpoint that you're building up a transformation of a value. In practice it's identical as long as function composition is being inlined and simplified as expected.






share|improve this answer























  • Strange, I thought that, since you had an empty list as an argument of "hanoiToList", you had to put something in its place ('l' in my case), so that it matched. Is this correct?
    – Marco_O
    Nov 8 at 1:26










  • @Marco_O nah. Functions are values that can be returned from other functions. If you never inspect an argument, it's often possible to never even name it.
    – Carl
    Nov 8 at 2:33










  • Thank you! I noticed something that was off about my code. I'm going to edit it to show you the changes.
    – Marco_O
    Nov 8 at 9:16












  • @Marco_O Ah, yes. Made the same edit to my answer.
    – Carl
    Nov 8 at 12:51






  • 1




    @Marco_O hanoiToList 0 _ _ _ l = l === hanoiToList 0 _ _ _ = l -> l === hanoiToList 0 _ _ _ = id. it's the same thing. So even if you have hanoiToList n a b c as your top call, what's being matched in the definition is hanoiToList n a b c, which is evaluated, returns a function, and that function gets applied to . looks different, but is the same.
    – Will Ness
    Nov 8 at 15:21

















up vote
3
down vote













Yep, that gets rid of the inefficient copying of (:) constructors. It's a slightly non-idiomatic way to write it, but the more idiomatic way should have identical performance when compiled with optimizations.



hanoi n a b c = hanoiToList n a b c 
where
hanoiToList 0 _ _ _ = id
hanoiToList n a b c = hanoiToList (n-1) a c b . ((a, b) :) . hanoiToList (n-1) c b a


That's the slightly more idiomatic approach. It's all about emphasizing the viewpoint that you're building up a transformation of a value. In practice it's identical as long as function composition is being inlined and simplified as expected.






share|improve this answer























  • Strange, I thought that, since you had an empty list as an argument of "hanoiToList", you had to put something in its place ('l' in my case), so that it matched. Is this correct?
    – Marco_O
    Nov 8 at 1:26










  • @Marco_O nah. Functions are values that can be returned from other functions. If you never inspect an argument, it's often possible to never even name it.
    – Carl
    Nov 8 at 2:33










  • Thank you! I noticed something that was off about my code. I'm going to edit it to show you the changes.
    – Marco_O
    Nov 8 at 9:16












  • @Marco_O Ah, yes. Made the same edit to my answer.
    – Carl
    Nov 8 at 12:51






  • 1




    @Marco_O hanoiToList 0 _ _ _ l = l === hanoiToList 0 _ _ _ = l -> l === hanoiToList 0 _ _ _ = id. it's the same thing. So even if you have hanoiToList n a b c as your top call, what's being matched in the definition is hanoiToList n a b c, which is evaluated, returns a function, and that function gets applied to . looks different, but is the same.
    – Will Ness
    Nov 8 at 15:21















up vote
3
down vote










up vote
3
down vote









Yep, that gets rid of the inefficient copying of (:) constructors. It's a slightly non-idiomatic way to write it, but the more idiomatic way should have identical performance when compiled with optimizations.



hanoi n a b c = hanoiToList n a b c 
where
hanoiToList 0 _ _ _ = id
hanoiToList n a b c = hanoiToList (n-1) a c b . ((a, b) :) . hanoiToList (n-1) c b a


That's the slightly more idiomatic approach. It's all about emphasizing the viewpoint that you're building up a transformation of a value. In practice it's identical as long as function composition is being inlined and simplified as expected.






share|improve this answer














Yep, that gets rid of the inefficient copying of (:) constructors. It's a slightly non-idiomatic way to write it, but the more idiomatic way should have identical performance when compiled with optimizations.



hanoi n a b c = hanoiToList n a b c 
where
hanoiToList 0 _ _ _ = id
hanoiToList n a b c = hanoiToList (n-1) a c b . ((a, b) :) . hanoiToList (n-1) c b a


That's the slightly more idiomatic approach. It's all about emphasizing the viewpoint that you're building up a transformation of a value. In practice it's identical as long as function composition is being inlined and simplified as expected.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 8 at 12:51

























answered Nov 8 at 1:16









Carl

19.6k34768




19.6k34768












  • Strange, I thought that, since you had an empty list as an argument of "hanoiToList", you had to put something in its place ('l' in my case), so that it matched. Is this correct?
    – Marco_O
    Nov 8 at 1:26










  • @Marco_O nah. Functions are values that can be returned from other functions. If you never inspect an argument, it's often possible to never even name it.
    – Carl
    Nov 8 at 2:33










  • Thank you! I noticed something that was off about my code. I'm going to edit it to show you the changes.
    – Marco_O
    Nov 8 at 9:16












  • @Marco_O Ah, yes. Made the same edit to my answer.
    – Carl
    Nov 8 at 12:51






  • 1




    @Marco_O hanoiToList 0 _ _ _ l = l === hanoiToList 0 _ _ _ = l -> l === hanoiToList 0 _ _ _ = id. it's the same thing. So even if you have hanoiToList n a b c as your top call, what's being matched in the definition is hanoiToList n a b c, which is evaluated, returns a function, and that function gets applied to . looks different, but is the same.
    – Will Ness
    Nov 8 at 15:21




















  • Strange, I thought that, since you had an empty list as an argument of "hanoiToList", you had to put something in its place ('l' in my case), so that it matched. Is this correct?
    – Marco_O
    Nov 8 at 1:26










  • @Marco_O nah. Functions are values that can be returned from other functions. If you never inspect an argument, it's often possible to never even name it.
    – Carl
    Nov 8 at 2:33










  • Thank you! I noticed something that was off about my code. I'm going to edit it to show you the changes.
    – Marco_O
    Nov 8 at 9:16












  • @Marco_O Ah, yes. Made the same edit to my answer.
    – Carl
    Nov 8 at 12:51






  • 1




    @Marco_O hanoiToList 0 _ _ _ l = l === hanoiToList 0 _ _ _ = l -> l === hanoiToList 0 _ _ _ = id. it's the same thing. So even if you have hanoiToList n a b c as your top call, what's being matched in the definition is hanoiToList n a b c, which is evaluated, returns a function, and that function gets applied to . looks different, but is the same.
    – Will Ness
    Nov 8 at 15:21


















Strange, I thought that, since you had an empty list as an argument of "hanoiToList", you had to put something in its place ('l' in my case), so that it matched. Is this correct?
– Marco_O
Nov 8 at 1:26




Strange, I thought that, since you had an empty list as an argument of "hanoiToList", you had to put something in its place ('l' in my case), so that it matched. Is this correct?
– Marco_O
Nov 8 at 1:26












@Marco_O nah. Functions are values that can be returned from other functions. If you never inspect an argument, it's often possible to never even name it.
– Carl
Nov 8 at 2:33




@Marco_O nah. Functions are values that can be returned from other functions. If you never inspect an argument, it's often possible to never even name it.
– Carl
Nov 8 at 2:33












Thank you! I noticed something that was off about my code. I'm going to edit it to show you the changes.
– Marco_O
Nov 8 at 9:16






Thank you! I noticed something that was off about my code. I'm going to edit it to show you the changes.
– Marco_O
Nov 8 at 9:16














@Marco_O Ah, yes. Made the same edit to my answer.
– Carl
Nov 8 at 12:51




@Marco_O Ah, yes. Made the same edit to my answer.
– Carl
Nov 8 at 12:51




1




1




@Marco_O hanoiToList 0 _ _ _ l = l === hanoiToList 0 _ _ _ = l -> l === hanoiToList 0 _ _ _ = id. it's the same thing. So even if you have hanoiToList n a b c as your top call, what's being matched in the definition is hanoiToList n a b c, which is evaluated, returns a function, and that function gets applied to . looks different, but is the same.
– Will Ness
Nov 8 at 15:21






@Marco_O hanoiToList 0 _ _ _ l = l === hanoiToList 0 _ _ _ = l -> l === hanoiToList 0 _ _ _ = id. it's the same thing. So even if you have hanoiToList n a b c as your top call, what's being matched in the definition is hanoiToList n a b c, which is evaluated, returns a function, and that function gets applied to . looks different, but is the same.
– Will Ness
Nov 8 at 15:21




















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53200042%2fis-this-haskell-tower-of-hanoi-solution-more-efficient-or-simply-redundant%23new-answer', 'question_page');
}
);

Post as a guest




















































































Popular posts from this blog

鏡平學校

ꓛꓣだゔៀៅຸ໢ທຮ໕໒ ,ໂ'໥໓າ໼ឨឲ៵៭ៈゎゔit''䖳𥁄卿' ☨₤₨こゎもょの;ꜹꟚꞖꞵꟅꞛေၦေɯ,ɨɡ𛃵𛁹ޝ޳ޠ޾,ޤޒޯ޾𫝒𫠁သ𛅤チョ'サノބޘދ𛁐ᶿᶇᶀᶋᶠ㨑㽹⻮ꧬ꧹؍۩وَؠ㇕㇃㇪ ㇦㇋㇋ṜẰᵡᴠ 軌ᵕ搜۳ٰޗޮ޷ސޯ𫖾𫅀ल, ꙭ꙰ꚅꙁꚊꞻꝔ꟠Ꝭㄤﺟޱސꧨꧼ꧴ꧯꧽ꧲ꧯ'⽹⽭⾁⿞⼳⽋២៩ញណើꩯꩤ꩸ꩮᶻᶺᶧᶂ𫳲𫪭𬸄𫵰𬖩𬫣𬊉ၲ𛅬㕦䬺𫝌𫝼,,𫟖𫞽ហៅ஫㆔ాఆఅꙒꚞꙍ,Ꙟ꙱エ ,ポテ,フࢰࢯ𫟠𫞶 𫝤𫟠ﺕﹱﻜﻣ𪵕𪭸𪻆𪾩𫔷ġ,ŧآꞪ꟥,ꞔꝻ♚☹⛵𛀌ꬷꭞȄƁƪƬșƦǙǗdžƝǯǧⱦⱰꓕꓢႋ神 ဴ၀க௭எ௫ឫោ ' េㇷㇴㇼ神ㇸㇲㇽㇴㇼㇻㇸ'ㇸㇿㇸㇹㇰㆣꓚꓤ₡₧ ㄨㄟ㄂ㄖㄎ໗ツڒذ₶।ऩछएोञयूटक़कयँृी,冬'𛅢𛅥ㇱㇵㇶ𥄥𦒽𠣧𠊓𧢖𥞘𩔋цѰㄠſtʯʭɿʆʗʍʩɷɛ,əʏダヵㄐㄘR{gỚṖḺờṠṫảḙḭᴮᵏᴘᵀᵷᵕᴜᴏᵾq﮲ﲿﴽﭙ軌ﰬﶚﶧ﫲Ҝжюїкӈㇴffצּ﬘﭅﬈軌'ffistfflſtffतभफɳɰʊɲʎ𛁱𛁖𛁮𛀉 𛂯𛀞నఋŀŲ 𫟲𫠖𫞺ຆຆ ໹້໕໗ๆทԊꧢꧠ꧰ꓱ⿝⼑ŎḬẃẖỐẅ ,ờỰỈỗﮊDžȩꭏꭎꬻ꭮ꬿꭖꭥꭅ㇭神 ⾈ꓵꓑ⺄㄄ㄪㄙㄅㄇstA۵䞽ॶ𫞑𫝄㇉㇇゜軌𩜛𩳠Jﻺ‚Üမ႕ႌႊၐၸဓၞၞၡ៸wyvtᶎᶪᶹစဎ꣡꣰꣢꣤ٗ؋لㇳㇾㇻㇱ㆐㆔,,㆟Ⱶヤマފ޼ޝަݿݞݠݷݐ',ݘ,ݪݙݵ𬝉𬜁𫝨𫞘くせぉて¼óû×ó£…𛅑הㄙくԗԀ5606神45,神796'𪤻𫞧ꓐ㄁ㄘɥɺꓵꓲ3''7034׉ⱦⱠˆ“𫝋ȍ,ꩲ軌꩷ꩶꩧꩫఞ۔فڱێظペサ神ナᴦᵑ47 9238їﻂ䐊䔉㠸﬎ffiﬣ,לּᴷᴦᵛᵽ,ᴨᵤ ᵸᵥᴗᵈꚏꚉꚟ⻆rtǟƴ𬎎

Why https connections are so slow when debugging (stepping over) in Java?