Thanks for the suggestion. I have added NoPolyKinds to the initial solution.
I didn't need it in my solution, but haven't investigated where exactly the issue comes from, yet.
This solution breaks on GHC 9.0, which is unfortunate because I really like it.
Even after reading the migration guide I have no clue what causes the issue in this case. Does someone know how to fix this solution on GHC 9.0+?
• Couldn't match type ‘Int -> Int’ with ‘Int’
arising from a functional dependency between:
constraint ‘Variadic Int Int (Int -> Int)’
arising from a use of ‘polyAdd’
instance ‘Variadic a r r’
at oneFunctionManyArguments.hs:14:10-23
• In the expression: polyAdd 1
In an equation for ‘a’: a = polyAdd 1
It looks very similar to the range function from python to me (excluding the step = 0 case).
So I don't think it is that strange to want such behavior.
Looks like your code is mutating the list, which is not allowed by the kata and the reason for the weird side effect you are seeing.
Trying running this on your code, which will give the wrong answer, just like in the test you posted:
Good point. I made sure that each of these operations works with at least two different types (like Int and Float). That should be enough right?
To make my life easier when testing I also added the (.=) function to implement. With that we also can have a nice isEven program, which I added aswell.
Last change is to the export/import list. Now everything is exported/imported by default, so that I don't have to touch these anymore if I decide to change an export again.
I used data so that I can define the left-hand side of the type while leaving the right-hand side out. newtype won't let me do that, but for the solution either newtype or data is fine.
The module Skeleton was a mistake on my part. I replaced it with the correct module Imperative.
I removed the unexported functions from the initial solution, I didn't have a good reason to include them.
I also added the missing type definition for def.
Lasty, probably the biggest change, I removed the TODO types. while/if/else are now fully typed.
That means that the typeclass I used also appears in the initial solution.
The Imperative type is still hidden, because I think it's interesting to figure out how to implement it.
Does it look better now?
I am a bit worried that the variable/value typeclass thing is a bit too much at once.
Oh and with the removal of the TODO types the initial solution now compiles, which I think is great.
You'd have to lift the built-in comparator and the value into the monad, of course, but that can be done polymorphically, so painlessly.
I can image this being done by redefining the operators (for example (<) = someLiftFunction P.(<)), which I would like to avoid.
How can it be done more painlessly?
Maybe my approach is already more complicated than it needs to be. For example while someVar (< 0) is a bit simpler because it only accepts a Var on the left side.
The meat of the kata should be defining mutable variabes and the if/else control flow, while keeping some kind of clean python-like syntax.
Let me know if you feel like there is anything else in the kata that makes it more convoluted than necessary.
I use the more complicated signature to make it possible to compare both variables and values using built-in functions like (<).
With Bool we wouldn't be able to compare the mutable variables we create. For example:
prog=defdoa<-var1-- a has type `Var st Int`whilea (<) 3do-- here we compare `Var st Int` with `Int`...
Does this make sense? If so I would add a hint for that.
It looks like this kata tried a different approach in the past, where Vars were instances of Num, but ended up with a version that's similar to what I am using here.
Thanks for the suggestion. I have added
NoPolyKinds
to the initial solution.I didn't need it in my solution, but haven't investigated where exactly the issue comes from, yet.
The initial solution exports everything, so that isn't a problem, is it?
This comment is hidden because it contains spoiler information about the solution
Thanks for the feedback!
I added these clarifications to the initial code for
.=
andtoString
.This solution breaks on GHC 9.0, which is unfortunate because I really like it.
Even after reading the migration guide I have no clue what causes the issue in this case. Does someone know how to fix this solution on GHC 9.0+?
It looks very similar to the
range
function from python to me (excluding the step = 0 case).So I don't think it is that strange to want such behavior.
This is a cool kata! I found a two points of frustrations, though.
Looks like your code is mutating the list, which is not allowed by the kata and the reason for the weird side effect you are seeing.
Trying running this on your code, which will give the wrong answer, just like in the test you posted:
I tried using the constructor and ran into this, too.
You don't need the constructor, though.
The kata is solvable with just the provided imports, so I don't think this is an issue.
Ah yes you are right. I changed the imports to back to being explicit.
Good point. I made sure that each of these operations works with at least two different types (like Int and Float). That should be enough right?
To make my life easier when testing I also added the (.=) function to implement. With that we also can have a nice
isEven
program, which I added aswell.Last change is to the export/import list. Now everything is exported/imported by default, so that I don't have to touch these anymore if I decide to change an export again.
(These changes invalidated your solution)
I used
data
so that I can define the left-hand side of the type while leaving the right-hand side out.newtype
won't let me do that, but for the solution eithernewtype
ordata
is fine.The
module Skeleton
was a mistake on my part. I replaced it with the correctmodule Imperative
.I removed the unexported functions from the initial solution, I didn't have a good reason to include them.
I also added the missing type definition for
def
.Lasty, probably the biggest change, I removed the TODO types. while/if/else are now fully typed.
That means that the typeclass I used also appears in the initial solution.
The
Imperative
type is still hidden, because I think it's interesting to figure out how to implement it.Does it look better now?
I am a bit worried that the variable/value typeclass thing is a bit too much at once.
Oh and with the removal of the TODO types the initial solution now compiles, which I think is great.
I can image this being done by redefining the operators (for example
(<) = someLiftFunction P.(<)
), which I would like to avoid.How can it be done more painlessly?
Maybe my approach is already more complicated than it needs to be. For example
while someVar (< 0)
is a bit simpler because it only accepts aVar
on the left side.The meat of the kata should be defining mutable variabes and the if/else control flow, while keeping some kind of clean python-like syntax.
Let me know if you feel like there is anything else in the kata that makes it more convoluted than necessary.
Thanks for the feedback!
I use the more complicated signature to make it possible to compare both variables and values using built-in functions like (<).
With Bool we wouldn't be able to compare the mutable variables we create. For example:
Does this make sense? If so I would add a hint for that.
It looks like this kata tried a different approach in the past, where
Var
s were instances ofNum
, but ended up with a version that's similar to what I am using here.Loading more items...