ztth222
ztth222

Reputation: 33

Beginner to Haskell type system : "Haskell non-type variable argument in constraint" Error

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:

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?

Upvotes: 3

Views: 67

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120741

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.

Upvotes: 4

Related Questions