Haskell: Non type-variable argument in the constraint - haskell

I created some functions to get some comfort with 2D geometry.
In this example I use Geom2D from CubicBezier package.
Complete code of my program: https://gist.github.com/nskeip/3784d651ac646a67c5f246f048949af4
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
import Geom2D
left :: (Num a) => Point a -> a -> Point a
left (Point x y) n = Point (x - n) y
right :: (Num a) => Point a -> a -> Point a
right (Point x y) n = Point (x + n) y
up :: (Num a) => Point a -> a -> Point a
up (Point x y) n = Point x (y - n)
down :: (Num a) => Point a -> a -> Point a
down (Point x y) n = Point x (y + n)
They work like this:
> (Point 0 0) `up` 10
Point 0.0 -10.0
Where Point is defined like this:
data Point a = Point {
pointX :: !a,
pointY :: !a
} deriving (Eq, Ord, Functor, Foldable, Traversable)
And everything was fine untill I thought: "Hey, it would be nice to make that functions (actualy, operators) work with thigs like Line - not only Point"
So I declared a class (not taking left and right to keep thigs simple):
class Num n => Moving p n where
up' :: n -> p -> p
down' :: n -> p -> p
up' n = down' (-n)
down' n = up' (-n)
And an instance of Moving for Point a data type:
instance Num a => Moving (Point a) a where
up' n (Point x y) = Point x (y - n)
But when I try to use it, I got an error:
✗ ghci ./uno.hs
GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Main ( uno.hs, interpreted )
Ok, modules loaded: Main.
*Main> let p = Point { pointX = 0, pointY = 0 }
*Main> up' 10 p
<interactive>:3:1:
Non type-variable argument in the constraint: Moving (Point a) n
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall n a. (Num a, Moving (Point a) n) => Point a
And the thing that confuses me much: I put the FlexibleContexts pragma to the pragma listing in the head, but ghcu still suggest me to get it included.
How can I fix my class / instance to get parametric polymorphism working? :)

And the thing that confuses me much: I put the FlexibleContexts pragma to the pragma listing in the head, but ghcu still suggest me to get it included.
This only enables the extension in the module itself. To write this code in GHCi, you need to enable the extension in GHCi: :set -XFlexibleContexts.
But this is only part of the problem. It looks like for your class p should determine n: you can only move a Point a up and down by a, right? But as it stands, nothing stops you from defining more Moving (Point a) SomeOtherType instances, and the compiler doesn't assume you won't. So a and n in the inferred type are completely unrelated, where you want them to be the same. This can be fixed by adding the FunctionalDependencies extension and changing the class declaration to say
class Num n => Moving p n | p -> n where
which means exactly that there can't be instances with same p and different n.
I think that's enough to make it work. The code will still be underdetermined because it allows any numeric a, but defaulting rules will pick Integer.

Related

Type mismatch in signature and locally introduced term

Consider the following code:
-- | Parse a 64bit word in little-endian format.
word64le :: Get ByteString e Word64
word64le = do
s <- elems 8
pure $ foldl' (.|.) 0 [shiftL (fromIntegral b) (i * 8) | (i, b) <- zip [0 .. 7] (atomize s)]
Per the comment, this reads out a Word64 from a ByteString by first pulling an 8-byte ByteString (the elems call), then unpacking it (the atomize call) and doing the obvious shift left dance. So far so good. Now this code can very obviously be generalized to other machine integral types, we just need to get hold of the number of bits of such a type and that is supplied by the FiniteBits class. So doing the generalization:
-- | Parse an integral word in little-endian format.
integralLe :: (FiniteBits w, Integral w, Bounded w) => Get ByteString e w
integralLe = do
s <- elems (fromIntegral n)
pure $ foldl' (.|.) 0 [shiftL (fromIntegral b) (i * 8) | (i, b) <- zip [0 .. n - 1] (atomize s)]
where
n = finiteBitSize (minBound :: w) `quot` 8
This does not work, with GHC complaining that "Could not deduce (Bounded w1) arising from a use of ‘minBound’ from the context: (FiniteBits w, Integral w, Bounded w)". So it seems that my type annotation minBound :: w is not enough to convince GHC that I mean the same w as in the function signature; is my diagnosis correct? And if yes, how do I tell GHC that the two w types are the same?
note(s):
on GHC 9.2 with a nightly stackage.
sorry about the poor question title, but cannot think of anything better.
edit(s):
per the comment added {-# LANGUAGE ScopedTypeVariables #-} at the top of the file but having the same error, namely "Could not deduce (Bounded w2) arising from a use of ‘minBound’ from the context: (FiniteBits w, Integral w, Bounded w) bound by the type signature for:"
Aha. If I add an explicit forall e w . in the function signature to the left of the constraint it works, even without the ScopedTypedVariables extensions (maybe because I am using language GHC2021). No on, to understand why the heck this works...
Haskell has some... let's charitably call it "weird"... rules for how type variables are scoped by default.
-- | Parse an integral word in little-endian format.
integralLe :: (FiniteBits w, Integral w, Bounded w) => Get ByteString e w
integralLe = do
s <- elems (fromIntegral n)
pure $ foldl' (.|.) 0 [shiftL (fromIntegral b) (i * 8) | (i, b) <- zip [0 .. n - 1] (atomize s)]
where
n = finiteBitSize (minBound :: w) `quot` 8
You're right that Haskell will throw an implicit forall w at the start of the integralLe type signature, but it's not actually a ScopedTypeVariables forall. By default, the scope of that variable is just that one line. It is not considered a type variable inside of any type ascriptions or signatures in where clauses, let clauses, or anything else inside the function. That's where ScopedTypeVariables comes in. With ScopedTypeVariables, an explicit forall makes the type variable available lexically to anything inside of the function body, including where blocks. (And, as you've correctly noted, ScopedTypeVariables is included in GHC2021). Hence,
integralLe :: forall w. (FiniteBits w, Integral w, Bounded w) => Get ByteString e w
will work.

Is it possible to promote a value to type level?

Doing this just for fun but I don't end up figuring this out.
Say I have a typeclass that unifies coordinate system on squares and hexagons:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Proxy
data Shape = Square | Hexagon
class CoordSystem (k :: Shape) where
type Coord k
-- all coordinates arranged in a 2D list
-- given a side length of the shape
allCoords :: forall p. p k -> Int -> [[Coord k]]
-- neighborhoods of a coordinate.
neighborsOf :: forall p. p k -> Int -> Coord k -> [Coord k]
-- omitting implementations
instance CoordSystem 'Square
instance CoordSystem 'Hexagon
Now suppose I want to use this interface with a s :: Shape that is only known at runtime. But to make use of this interface, at some point I'll need a function like this:
-- none of those two works:
-- promote :: CoordSystem k => Shape -> Proxy (k :: Shape) -- signature 1
-- promote :: Shape -> forall k. CoordSystem k => Proxy (k :: Shape)
promote s = case s of
Square -> Proxy #'Square
Hexagon -> Proxy #'Hexagon
However this does not work, if signature 1 is uncommented:
• Couldn't match type ‘k’ with ‘'Square’
‘k’ is a rigid type variable bound by
the type signature for:
promote :: forall (k :: Shape). CoordSystem k => Shape -> Proxy k
at SO.hs:28:1-55
Expected type: Proxy k
Actual type: Proxy 'Square
Understandably, none of 'Square, 'Hexagon, k :: Shape unifies with others, so I have no idea whether this is possible.
I also feel type erasure shouldn't be an issue here as alternatives of Shape can use to uniquely identify the instance - for such reason I feel singletons could be of use but I'm not familiar with that package to produce any working example either.
The usual way is to use either an existential type or its Church encoding. The encoded version is actually easier to understand at first, I think, and closer to what you already attempted. The problem with your forall k. CoordSystem k => {- ... thing mentioning k -} is that it promises to polymorph into whatever k the user likes (so long as the user likes CoordSystems!). To fix it, you can demand that the user polymorph into whatever k you like.
-- `a` must not mention `k`, since `k` is not
-- in scope in the final return type
promote :: forall a. Shape -> (forall k. CoordSystem k => Tagged k a) -> a
promote Square a = unTagged (a #Square)
promote Hexagon a = unTagged (a #Hexagon)
-- usage example
test = promote Hexagon (unproxy $ \p -> length (allCoords p 15))
Note that on the right hand side of the = sign, a has the type forall k. CoordSystem k => {- ... -} that says the user gets to choose k, but this time you're the user.
Another common option is to use an existential:
data SomeSystem where
-- Proxy to be able to name the wrapped type when matching on a SomeSystem;
-- in some future version of GHC we may be able to name it via pattern-matching
-- on a type application instead, which would be better
SomeSystem :: CoordSystem k => Proxy k -> SomeSystem
Then you would write something like
promote :: Shape -> SomeSystem
promote Square = SomeSystem (Proxy #Square)
promote Hexagon = SomeSystem (Proxy #Hexagon)
-- usage example
test = case promote Hexagon of SomeSystem p -> length (allCoords p 15)
and then the user would pattern match to extract the CoordSystem instance from it.
A final choice is singletons:
data ShapeS k where
SquareS :: ShapeS Square
HexagonS :: ShapeS Hexagon
Here we have made a direct connection between SquareS at the computation level and Square at the type level (resp. HexagonS and Hexagon). Then you can write:
-- N.B. not a rank-2 type, and in particular `a` is
-- now allowed to mention `k`
promote :: ShapeS k -> (CoordSystem k => a) -> a
promote SquareS a = a
promote HexagonS a = a
The singletons package offers tools for automatically deriving the singleton types that correspond to your ADTs.

DataKind Unions

I'm not sure if it is the right terminology, but is it possible to declare function types that take in an 'union' of datakinds?
For example, I know I can do the following:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
...
data Shape'
= Circle'
| Square'
| Triangle'
data Shape :: Shape' -> * where
Circle :: { radius :: Int} -> Shape Circle'
Square :: { side :: Int} -> Shape Square'
Triangle
:: { a :: Int
, b :: Int
, c :: Int}
-> Shape Triangle'
test1 :: Shape Circle' -> Int
test1 = undefined
However, what if I want to take in a shape that is either a circle or a square? What if I also want to take in all shapes for a separate function?
Is there a way for me to either define a set of Shape' kinds to use, or a way for me to allow multiple datakind definitions per data?
Edit:
The usage of unions doesn't seem to work:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
...
type family Union (a :: [k]) (r :: k) :: Constraint where
Union (x ': xs) x = ()
Union (x ': xs) y = Union xs y
data Shape'
= Circle'
| Square'
| Triangle'
data Shape :: Shape' -> * where
Circle :: { radius :: Int} -> Shape Circle'
Square :: { side :: Int} -> Shape Square'
Triangle
:: { a :: Int
, b :: Int
, c :: Int}
-> Shape Triangle'
test1 :: Union [Circle', Triangle'] s => Shape s -> Int
test1 Circle {} = undefined
test1 Triangle {} = undefined
test1 Square {} = undefined
The part above compiles
You can accomplish something like this in (I think) a reasonably clean way using a type family together with ConstraintKinds and PolyKinds:
type family Union (a :: [k]) (r :: k) :: Constraint where
Union (x ': xs) x = ()
Union (x ': xs) y = Union xs y
test1 :: Union [Circle', Triangle'] s => Shape s -> Int
test1 = undefined
The () above is the empty constraint (it's like an empty "list" of type class constraints).
The first "equation" of the type family makes use of the nonlinear pattern matching available in type families (it uses x twice on the left hand side). The type family also makes use of the fact that if none of the cases match, it will not give you a valid constraint.
You should also be able to use a type-level Boolean instead of ConstraintKinds. That would be a bit more cumbersome and I think it would be best to avoid using a type-level Boolean here (if you can).
Side-note (I can never remember this and I had to look it up for this answer): You get Constraint in-scope by importing it from GHC.Exts.
Edit: Partially disallowing unreachable definitions
Here is a modification to get it to (partially) disallow unreachable definitions as well as invalid calls. It is slightly more roundabout, but it seems to work.
Modify Union to give a * instead of a constraint, like this:
type family Union (a :: [k]) (r :: k) :: * where
Union (x ': xs) x = ()
Union (x ': xs) y = Union xs y
It doesn't matter too much what the type is, as long as it has an inhabitant you can pattern match on, so I give back the () type (the unit type).
This is how you would use it:
test1 :: Shape s -> Union [Circle', Triangle'] s -> Int
test1 Circle {} () = undefined
test1 Triangle {} () = undefined
-- test1 Square {} () = undefined -- This line won't compile
If you forget to match on it (like, if you put a variable name like x instead of matching on the () constructor), it is possible that an unreachable case can be defined. It will still give a type error at the call-site when you actually try to reach that case, though (so, even if you don't match on the Union argument, the call test1 (Square undefined) () will not type check).
Note that it seems the Union argument must come after the Shape argument in order for this to work (fully as described, anyway).
This is getting kind of awful, but I guess you could require a proof that it's either a circle or a square using Data.Type.Equality:
test1 :: Either (s :~: Circle') (s :~: Square') -> Shape s -> Int
Now the user has to give an extra argument (a "proof term") saying which one it is.
In fact you can use the proof term idea to "complete" bradm's solution, with:
class MyOpClass sh where
myOp :: Shape sh -> Int
shapeConstraint :: Either (sh :~: Circle') (sh :~: Square')
Now nobody can go adding any more instances (unless they use undefined, which would be impolite).
You could use typeclasses:
class MyOpClass sh where
myOp :: Shape sh -> Int
instance MyOpClass Circle' where
myOp (Circle r) = _
instance MyOpClass Square' where
myOP (Square s) = _
This doesn't feel like a particularly 'complete' solution to me - anyone could go back and add another instance MyOpClass Triangle' - but I can't think of any other solution. Potentially you could avoid this problem simply by not exporting the typeclass however.
Another solution I've noticed, though pretty verbose, is to create a kind that has a list of feature booleans. You can then pattern match on the features when restricting the type:
-- [circleOrSquare] [triangleOrSquare]
data Shape' =
Shape'' Bool
Bool
data Shape :: Shape' -> * where
Circle :: { radius :: Int} -> Shape (Shape'' True False)
Square :: { side :: Int} -> Shape (Shape'' True True)
Triangle
:: { a :: Int
, b :: Int
, c :: Int}
-> Shape (Shape'' False True)
test1 :: Shape (Shape'' True x) -> Int
test1 Circle {} = 2
test1 Square {} = 2
test1 Triangle {} = 2
Here, Triangle will fail to match:
• Couldn't match type ‘'True’ with ‘'False’
Inaccessible code in
a pattern with constructor:
Triangle :: Int -> Int -> Int -> Shape ('Shape'' 'False 'True),
in an equation for ‘test1’
• In the pattern: Triangle {}
In an equation for ‘test1’: test1 Triangle {} = 2
|
52 | test1 Triangle {} = 2
| ^^^^^^^^^^^
Unfortunately, I don't think you can write this as a record, which may be clearer and avoids the ordering of the features.
This might be usable in conjunction with the class examples for readability.

How to overload a function for multiplying [Double] in Haskell (ad-hoc polymorphism)?

The way to have ad-hoc polymorphism (function overloading) in Haskell is through type classes (see answers to this, this and this question, among others).
But I'm struggling to define an overloaded mult (product) function for the following cases:
mult: [Double] -> Double -> [Double]
mult: Double -> [Double] -> [Double]
mult: [Double] -> [Double] -> [Double]
Thanks
(At least, case 1 [Double]*Double and case 3 [Double]*[Double] would be necessary).
As always, statements like "I'm trying (with no success) this" are not quite as useful as you would like: it's good that you included your code, but if you are getting an error message from the compiler, tell us what it is! They're very instructive, and are printed for a reason.
I just tried what you wrote, and this is in fact the error message you are (probably) getting:
*Multiplication> mul 1 [2]
Non type-variable argument
in the constraint: Multipliable ta [t] tc
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall ta tc t. (Num ta, Num t, Multipliable ta [t] tc) => tc
Now, you could try just turning on FlexibleContexts, but that doesn't seem to solve the problem. But, as is often the case when the compiler is telling you it's having trouble inferring types, you should try adding some explicit types and see if that helps:
*Multiplication> mul (1::Double) [2 :: Double]
[2.0]
Basically, the compiler can't be sure which overload of mul you want: 1 and 2 are polymorphic and could be any numeric type, and while there is only one suitable overload for mul now, the compiler doesn't make such an inference unless it can prove no other overload could ever exist in this context. Fully specifying the argument types is enough to resolve the problem.
An alternative approach to this particular problem is to use a typeclass for each argument, to convert it into the canonical type [Double], rather than a typeclass for the arguments as a whole. This is a more specific solution than general ad hoc polymorphism, and not all problems will fit, but for something like treating a single number like a list of numbers it should be fine:
module Multiplication where
import Control.Monad (liftM2)
class AsDoubles a where
doubles :: a -> [Double]
instance AsDoubles Double where
doubles = return
instance AsDoubles [Double] where
doubles = id
mult :: (AsDoubles a, AsDoubles b) => a -> b -> [Double]
mult x y = liftM2 (*) (doubles x) (doubles y)
*Multiplication> mult [(1 :: Double)..5] [(1 :: Double)..3]
[1.0,2.0,3.0, -- whitespace added for readability
2.0,4.0,6.0,
3.0,6.0,9.0,
4.0,8.0,12.0,
5.0,10.0,15.0]
I've managed to do it this way. Certainly not very nice.
I think anyone should consider the comments and critics by leftaroundaobut to the question, that I quote below for convenience and relevance.
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}
class Multipliable ta tb tc | ta tb -> tc where
mul :: ta -> tb -> tc
instance Multipliable [Double] Double [Double] where
mul p k = map (*k) p --mul p k = map (\a -> k * a) p
instance Multipliable Double [Double] [Double] where
mul k p = map (*k) p --mul p k = map (\a -> k * a) p
instance Multipliable [Double] [Double] [Double] where
mul p q = p -- dummy implementation
r = [1.0, 2.0, 3.0] :: [Double]
r1 = (mul :: [Double] -> Double -> [Double]) r 2.0
r2 = (mul :: Double -> [Double] -> [Double]) 2.0 r
r3 = (mul :: [Double] -> [Double] -> [Double]) r1 r2
main = do
print r1
print r2
print r3
Why do you want this anyway? Just because Matlab allows multiplying
anything you throw at it doesn't mean this is a good idea. Check out
vector-space for properly dealing with
multidimensional-multiplications. Alternatively, if you don't care so
much for mathematical elegance, you can use hmatrix (which is in fact
a lot like Matlab/Octave in Haskell), or linear.
I think it's a bad idea in general, and really unnecessary in Haskell because you can just write map (*x) ys or zipWith (*) xs ys
to make you intent explicit. This of course doesn't work for
polymorphic code that's supposed to handle both scalars and vectors –
however, writing such code to just deal with scalars or lists of any
length is rather asking for trouble. It's awkward to specify which
list needs to have a length matching which other list and what length
the result will be etc.. This is where vector-space or linear shine,
because they check dimensions at compile time.

How do you use the Bounded typeclass in Haskell to define a type with a floating point range?

I expected the following code to fail with a type error due to violation of the minBound and maxBound. But, as you can see, it goes through without flagging an error.
{-# OPTIONS_GHC -XTypeSynonymInstances #-}
module Main where
type Probability = Float
instance Bounded Probability where
minBound = 0.0
maxBound = 1.0
testout :: Float -> Probability
testout xx = xx + 1.0
main = do
putStrLn $ show $ testout 0.5
putStrLn $ show $ testout (-1.5)
putStrLn $ show $ testout 1.5
In the Prelude I get this
*Main> :type (testout 0.5)
(testout 0.5) :: Probability
And at the prompt I get this:
[~/test]$runhaskell demo.hs
1.5
-0.5
2.5
Clearly I'm not declaring Bounded properly, and I'm sure I'm doing something wrong syntactically. There isn't much simple stuff on Google regarding Bounded typeclasses, so any help would be much appreciated.
That's not what Bounded is for. Bounded a just defines the functions minBound :: a and maxBound :: a. It does not induce any special checking or anything.
You can define a bounded type using a so-called smart constructor. That is:
module Probability (Probability) where
newtype Probability = P { getP :: Float }
deriving (Eq,Ord,Show)
mkP :: Float -> Probability
mkP x | 0 <= x && x <= 1 = P x
| otherwise = error $ show x ++ " is not in [0,1]"
-- after this point, the Probability data constructor is not to be used
instance Num Probability where
P x + P y = mkP (x + y)
P x * P y = mkP (x * y)
fromIntegral = mkP . fromIntegral
...
So the only way to make a Probability is to use the mkP function eventually (this is done for you when you use numeric operations given our Num instance), which checks that the argument is in range. Because of the module's export list, outside of this module is it not possible to construct an invalid probability.
Probably not the two-liner you were looking for, but oh well.
For extra composability, you could factor out this functionality by making a BoundCheck module instead of Probability. Just like above, except:
newtype BoundCheck a = BC { getBC :: a }
deriving (Bounded,Eq,Ord,Show)
mkBC :: (Bounded a) => a -> BoundCheck a
mkBC x | minBound <= x && x <= maxBound = BC x
| otherwise = error "..."
instance (Bounded a) => Num (BoundCheck a) where
BC x + BC y = mkBC (x + y)
...
Thus you can get the functionality you were wishing was built in for you when you asked the question.
To do this deriving stuff you may need the language extension {-# LANGUAGE GeneralizedNewtypeDeriving #-}.

Resources