In an attempt to dip my toes in functional programming, I'm attempting to pick up Haskell and running into some mental issues with the type system.
Running the following code gives proper output (e.g. generates coordinates for a circle wrapped around a cylinder of radius R at angle theta):
coilGeneration_AngleTest housingRadius coilWidth coilDepth numEle zoffset centralAngle
= [ (x',y',z)
| theta <- [0,2*pi/(numEle-1)..2*pi]
, let x = housingRadius * cos(coilWidth*cos(theta)/housingRadius)
, let y = housingRadius * sin(coilWidth*cos(theta)/housingRadius)
, let z = coilDepth * sin(theta)+zoffset
, let x' = x * cos(centralAngle) - y * sin(centralAngle)
, let y' = x * sin(centralAngle) + y * cos(centralAngle)
]
Sample coilGeneration_AngleTest function output
However, attempting to generalize this into a function that generates an arbitrary NxM array of circles with varying overlaps in the polar and z-directions by running:
coilArrayGeneration_Test r nE width depth n m mu gam
= [ (x',y',z',i,j)
| theta <- [0,2*pi/(nE-1)..2*pi]
, i <- [1..n]
, j <- [1..m]
, let a = width/2
, let b = depth/2
, let x = r * cos(a*cos(theta)/r)
, let y = r * sin(a*cos(theta)/r)
, let z = b * sin(theta)
, let phi = (2*i-1-n)((a-mu)/r)
, let zo = (2*j-1-m)(b-gam)
, let x' = x * cos(phi) - y * sin(phi)
, let y' = x * sin(phi) + y * cos(phi)
, let z' = z + zo
]
gives the following error:
Build profile: -w ghc-9.2.5 -O1
In order, the following will be built (use -v for more details):
- Haskell-0.1.0.0 (exe:Haskell) (file app/Main.hs changed)
Preprocessing executable 'Haskell' for Haskell-0.1.0.0..
Building executable 'Haskell' for Haskell-0.1.0.0..
[1 of 1] Compiling Main ( app/Main.hs, /Users/zack/Desktop/Udemy/Haskell/dist-newstyle/build/aarch64-osx/ghc-9.2.5/Haskell-0.1.0.0/x/Haskell/build/Haskell/Haskell-tmp/Main.o )
app/Main.hs:66:1: error:
• Non type-variable argument in the constraint: Num (c -> c)
(Use FlexibleContexts to permit this)
• When checking the inferred type
coilArrayGeneration_Test :: forall {c}.
(Floating c, Num (c -> c), Enum c, Enum (c -> c)) =>
c
-> c
-> c
-> c
-> (c -> c)
-> (c -> c)
-> c
-> c
-> [(c, c, c, c -> c, c -> c)]
|
66 | coilArrayGeneration_Test r nE width depth n m mu gam = [(x',y',z',i,j)|theta <- [0,2*pi/(nE-1)..2*pi],....
Failure Output
After googling for a while, it seemed that my function had an improper type implied by the compiler but I unfortunately don't understand the idea Haskell Type Definition well enough to fix it. I attempted to define the types the way I see them, namely:
r -> Double
nE -> Int
width -> Double
depth -> Double
n -> Int
m -> Int
mu -> Double
gam -> Double
x' -> Double
y' -> Double
z' -> Double
I -> Int
j -> Int
Getting:
coilArrayGeneration_Test :: (Floating a, Integral b) => a -> b -> a -> a -> b -> b -> a -> a -> [(a,a,a,b,b)]
coilArrayGeneration_Test r nE width depth n m mu gam
= [ (x',y',z',i,j)
| theta <- [0,2*pi/(nE-1)..2*pi]
, i <- [1..n]
, j <- [1..m]
, let a = width/2
, let b = depth/2
, let x = r * cos(a*cos(theta)/r)
, let y = r * sin(a*cos(theta)/r)
, let z = b * sin(theta)
, let phi = (2*i-1-n)((a-mu)/r)
, let zo = (2*j-1-m)(b-gam)
, let x' = x * cos(phi) - y * sin(phi)
, let y' = x * sin(phi) + y * cos(phi)
, let z' = z + zo
]
But this threw a whole host of errors:
Errors after Type Declaration
Which clearly means I don't know what I'm doing and mucked up the type declarations somehow.
Can anyone steer me the right way?
When you see a compiler error involving something like Num (c -> c), it never has anything to do with -XFlexibleContexts or with incorrect inferred types. It simply means you attempted to use something as a function which is not a function.
“Use as a function” entails simply that you have some expression of the form f x, where f and x can be arbitrary subexpressions. This includes in particular also expressions like (1+2)(3+4), which is the same as
let f = 1 + 2
x = 3 + 4
in f x
Presumably you meant to express multiplication by the juxtaposition. Well, use the multiplication operator then! I.e. (1+2)*(3+4).
Your code has also another problem: you trying to use the index variables in real-valued expression. Unlike the missing multiplication operators, this is fairly sensible, but Haskell doesn't allow this either. You need to explicitly wrap the integrals in fromIntegral.
coilArrayGeneration_Test r nE width depth n m μ γ
= [ (x',y',z',i,j)
| ϑ <- [0, 2*pi/fromIntegral(nE-1) .. 2*pi]
, i <- [1..n]
, j <- [1..m]
, let a = width/2
b = depth/2
x = r * cos(a*cos ϑ/r)
y = r * sin(a*cos ϑ/r)
z = b * sin ϑ
φ = fromIntegral(2*i-1-n) * ((a-μ)/r)
z₀ = fromIntegral(2*j-1-m) * (b-γ)
x' = x * cos φ - y * sin φ
y' = x * sin φ + y * cos φ
z' = z + z₀
]
I would strongly recommend you refactor this a bit, both code and types. 5-tuples are very obscure, you should at least wrap x,y,z in a suitable vector type.
I am trying to understand why my code doesn't work:
writeRow :: Int -> IO()
writeRow x = putStr(concat (replicate x "* "))
triangle :: Int -> IO()
triangle x = do
writeRow x
putStr ""
triangle x-1
My thinking is, that writeRow creates a row of x times " * ", so if x = 4, triangle 4 will write
* * * *
As triangle is called recursivly with x -1, the next line will be:
* * *
And so on ... until:
* * * *
* * *
* *
*
But it just outputs it all on one line:
* * * * * * * *
What seems to be the issue? :D
putStr only prints the string, it does not write a new line, you should use putStrLn. Furthermore you should use triangle (x-1) so with parenthesis around the x-1 part, and specify a base case for the recursion with the triangle:
writeRow :: Int -> IO()
writeRow x = putStr(concat (replicate x "* "))
triangle :: Int -> IO()
triangle x | x <= 0 = pure ()
triangle x = do
writeRow x
putStrLn ""
triangle (x-1)
With these modifications, we obtain:
Prelude> triangle 4
* * * *
* * *
* *
*
I wanted to Print to A pascal Triangle for a given Length.
main = do
l_str <- getLine
let l_int = read $ l_str :: Int
let why = print_row l_int 0
print why
return ()
print_row x y
| (x < y) = " "
| otherwise = (print_column y 0 ) ++ "\n" ++ print_row x (y+1)
print_column y r
| (y < r) = ""
| otherwise = (show $ fact y r ) ++ print_column y (r+1)
fact n r
| (n >= r) = truncate $ (fact' n)/((fact' (n-r))*(fact' r))
fact' n
| (n >= 0) = product [1..n]
I have checked all my functions "print_row" ,"print_column" everything works fine.
I am getting this error:
PascalTriangle.hs:4:17:
No instance for (RealFrac Int) arising from a use of ‘fact’
In the expression: fact l_int 0
In an equation for ‘why’: why = fact l_int 0
In the expression:
do { l_str <- getLine;
let l_int = ...;
let why = fact l_int 0;
print why;
.... }
I am not able Understand anything about this error.The pogram works fine when I use a constant instead of l_int in line 4.Like let why = print_row 4 0.
You need to use div instead of /.
div will take two Integral values and return another Integral value - e.g. div 5 2 == 2. Then you'll also need to get rid of the truncate call.
/ does "floating point" division.
fromIntegral will convert an Integral value to any other Num type.
This is to take a number, get its factorial and double it, however because of the base case if you input 0 it gives 2 as the answer so in order to bypass it i used an if statement, but get the error
parse error on input ‘if’. Really appreciate if you guys could help :)
fact :: Int -> Int
fact 0 = 1
fact n = n * fact(n-1)
doub :: Int -> Int
doub r = 2 * r
factorialDouble :: IO()
factorialDouble = do
putStr "Enter a Value: "
x <- getLine
let num = (read x) :: Int
if (num == 0) then error "factorial of zero is 0"
else let y = doub (fact num)
putStrLn ("the double of factorial of " ++ x ++ " is " ++ (show y))
I've spotted two issues
that should be addressed
You have a let that has no continuation:
(else let y = doub (fact num) ...).
Because you're not inside a do, you would probably want to change it into a let ... in statement.
Your if is indented too far in. It should be under the let.
I've corrected what I mentioned and the code works for me...
fact :: Int -> Int
fact 0 = 1
fact n = n * fact(n-1)
doub :: Int -> Int
doub r = 2 * r
factorialDouble :: IO ()
factorialDouble = do
putStr "Enter a Value: "
x <- getLine
let num = (read x) :: Int
if num == 0 then (error "factorial of zero is 0")
else let y = doub (fact num)
in putStrLn ("the double of factorial of " ++ x ++ " is " ++ (show y))
What is the best practice to display reasons for a failed property test when it is tested via QuickCheck?
Consider for example:
prop a b = res /= []
where
(res, reason) = checkCode a b
Then the a session could look like:
> quickCheck prop
Falsifiable, after 48 tests:
42
23
But for debugging it would be really convenient to show the reason for failure as part of the quickCheck falsifable report.
I have hacked it like this:
prop a b = if res /= [] then traceShow reason False else True
where
(res, reason) = checkCode a b
Is there is a better/nicer or more quickcheckish way to do it?
I assume that your "reason" variable contains some kind of test-specific data on what went wrong. You could instead return a "Result", which contains both success/fail/invalid conditions and a string explaining what went wrong. Properties that return Results are handled by QuickCheck in exactly the same way as properties that return Bool.
(edit) Like this:
module QtTest where
import Test.QuickCheck
import Test.QuickCheck.Property as P
-- Always return success
prop_one :: Integer -> P.Result
prop_one _ = MkResult (Just True) True "always succeeds" False [] []
-- Always return failure
prop_two :: Integer -> P.Result
prop_two n = MkResult (Just False) True ("always fails: n = " ++ show n) False [] []
Note that it is the "Result" type defined in Test.QuickCheck.Property you want.
There are also some combinators defined in Test.QuickCheck.Property which help you compose the Result rather than calling the constructor directly, such as
prop_three :: Integer -> Property
prop_three n = printTestCase ("always fails: n = " ++ show n) False
I guess it would be better style to use those.
This works in the same way as Paul Johnson's answer but is more concise and robust to changes in MkResult:
import Test.QuickCheck.Property (succeeded, failed, reason)
prop a b =
if res /= []
then succeeded
else failed { reason = reason }
where
(res, reason) = checkCode a b
Because QuickCheck gives you the inputs to the function, and because the code under test is pure (it is, right?), you can just feed those inputs to the function and get the result. This is more flexible, because with those inputs you can also repeatedly test with tweaks to the original function until it's correct.
This is my solution (I use counterexample instead of printTestCase since the later one is deprecated now):
(<?>) :: (Testable p) => p -> String -> Property
(<?>) = flip (Test.QuickCheck.counterexample . ("Extra Info: " ++))
infixl 2 <?>
Usage:
main :: IO ()
main = hspec $ do
describe "math" $ do
prop "sum-of-square-le-square-of-sum" $ do
\(x :: Int) (y :: Int) ->
x * x + y * y <= (x + y) * (x + y) <?> show (x * x, y * y, x + y)
So when a test case fails, you can see something like:
*** Failed! Falsifiable, Falsifiable (after 2 tests):
1
-1
Extra Info: (1,1,0)
You can also use <?> together with .&&., .||., === and ==> etc.:
describe "math" $ do
prop "sum-of-square-le-square-of-sum" $ do
\(x :: Int) (y :: Int) ->
x * x + y * y <= (x + y) * (x + y) <?> show (x * x, y * y, x + y) .||. (1==0) <?> "haha"