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

Guess what letter conforming each word

Port of Spain

Run scheduled task as local user group (not BUILTIN)