How do I implement a partially injective type family in Haskell? - haskell

I am implementing a varity of functions that require type safe natural numbers in Haskell, and have recently needed an Exponential type to represent a new type.
Below are the three type families that I have made up to this point for ease of reference.
type family Add n m where
Add 'One n = 'Succ n
Add ('Succ n) m = 'Succ (Add n m)
-- Multiplication, allowing ever more powerful operators
type family Mul n m where
Mul 'One m = m
Mul ('Succ n) m = Add m (Mul n m)
-- Exponentiation, allowing even even more powerful operators
type family Exp n m where
Exp n 'One = n
Exp n ('Succ m) = Mul n (Exp n m)
However, when using this type I came across the issue that it wasn't injective; this meant that some of the type inferences I kinda wanted didn't exist. (The error was NB: ‘Exp’ is a non-injective type family). I can ignore the issue by using -XAllowAmbiguousTypes, but I would prefer not to use this extension, so all the types can checked where the function is defined.
I think that Exp n m should be injective when m is constant, so I wanted to try to implement that, but I'm unsure as to how to do that after a lot of trial and error. Even if it doesn't solve my problem currently, it might be useful in future. Alternatively, Exp n m is injective for a given n where m changes, and n is not One.
Upon asking other people, they suggested that something like type family Exp n m = inj | inj, n -> m where but that doesn't work, giving a syntax error on the comma if it's there and a parse error on the final n if it isn't. This was intended to allow inj and n to uniquely identify a given m.
The function I am trying to implement but am having trouble with currently has a signature as follows.
tensorPower :: forall i a n m . (Num a, KnownNat i) => Matrix n m a -> Matrix (Exp n i) (Exp m i) a
This function can be called with tensorPower #Three a (when -XAllowAmbiguousTypes is set), but I'd like GHC to be able to determine the i value by itself if possible. For the purposes of this question it's fine to assume that a given a matrix isn't polymorphic.
Adjusting the constraint to the following doesn't work either; this was an attempt at creating injectivity in the type of the above function instead of where the type family is defined
forall i a n m
. ( Num a
, KnownNat i
, Exp n ( 'Succ i) ~ Mul n (Exp n i)
, Exp m ( 'Succ i) ~ Mul m (Exp m i)
, Exp n One ~ n
, Exp m One ~ m
)
So, is it possible to implement injectivity for this function, and if so, how do I implement it?
(To see more of the code in action, please visit the repository. The src folder has the majority of the source of the code, with the main areas being fiddled with in this question belonging to Lib.hs and Quantum.hs. The extensions used can (mostly) be found in the package.yaml)

There's actually a surprisingly simple way to get this to work in at least one way; the following type family, when used appropriately in a constraint, allows tensorPower to be used without an annotation.
-- Reverse the exponent - if it can't match then it goes infinitely
type family RLog n m x c where
RLog m n n i = i
RLog m n x i = RLog m n (Mul m x) ('Succ i)
type ReverseLog n m = RLog n m n 'One
type GetExp n i = ReverseLog n (Exp n i)
----------------
-- adjusted constraint for tensorPower
forall i a n m . (Num a, KnownNat i, i ~ GetExp n i, i ~ GetExp m i)
For example, now one can type (tensorPower hadamard) *.* (zero .*. zero .*. one) (where hadamard is Matrix Two Two Double, both zero and one are Matrix Two One Double, (*.*) is matrix multiplication, (.*.) is the tensor product and the type of i is completely inferred).
The way this type family works is that it has four parameters: the base, the target, the accumulator, and the current exponent. If the target and the accumulator are equal, then the current exponent is "returned". If they are not equal, we recurse by multiplying the current accumulator by the base, and increment the current exponent.
There is one issue with this solution that I can see: if it can't match up the "bases", it has a really horribly long error message as it recurses as deep as it can into types. This can be fixed by doing some other type trickery which is out of scope for this question, but can be seen in this commit on my project's repository.
In conclusion: introducing some abstract injectivity seemed to be a no-go, but implementing a sort of reversal of the exponent resulted in clean, simple, and functioning code - this is effectively injectivity, by proving that there is a reversible function for the Exp.
(One note is that this solution needs a bit more fiddling to work fully, since GetExp n i doesn't really work for n=='One; I've gotten around this by never having GetExp ('One) i in the first place)

Related

Why does Haskell 9.0 not have Zero in its linear types, but Idris 2 does?

From the Idris 2 publication about linear types "Idris 2: Quantitative Type Theory in Practice":
For Idris 2, we make a concrete choice of semiring, where a multiplicity can be one of:
0: the variable is not used at run time
1: the variable is used exactly once at run time
ω: no restrictions on the variable’s usage at run time
But for Haskell:
In the fashion of levity polymorphism, the proposal introduces a data type Multiplicity which is treated specially by the type checker, to represent the multiplicities:
data Multiplicity
= One -- represents 1
| Many -- represents ω
Why didn't they add a Zero?
In Idris, the value of a function argument can appear in the return type. You might write a function with type
vecLen : (n : Nat) -> Vect n a -> (m : Nat ** n = m)
This says "vecLen is a function that takes a Nat (call it n) and a Vect of length n and element type a and returns a Nat (call it m) such that n = m". The intent is to walk the linked list Vect and come up with its length as a runtime Nat value. But the issue is that vecLen requires you to already have the length of the vector as a runtime value, because that's the very n argument we're talking about! I.e. it's possible to implement just
vecLen n _ = (n ** Refl) -- does no real work
You can't not take n as an argument, because the Vect type needs its length as an argument to make sense. This is a somewhat serious problem, because having both n and a Vect n a duplicates information—without intervention the "classic" definition of Vect n a itself is in fact space-quadratic in n! So we need a way to take an argument that we know "in principle exists" but may not "actually exist" at runtime. That's what the zero multiplicity is for.
vecLen : (0 n : Nat) -> Vect n a -> (m : Nat ** n = m)
-- old definition invalid, you MUST iterate over the Vect to collect information on n (which is what we want!)
vecLen _ [] = (0 ** Refl)
vecLen _ (_ :: xs) with (vecLen _ xs)
vecLen _ (_ :: xs) | (n ** Refl) = (S n ** Refl)
This is the use of the zero multiplicity in Idris: it lets you talk about values that may not exist yet/anymore/ever inside of types so you can reason about them etc. (I believe in one talk Edwin Brady did, he used or at least noted you could use zero multiplicities to reason about the previous state of a mutable resource.)
But Haskell does not quite have this kind of dependent typing... so there just isn't a use case for zero multiplicities. From another point of view, the zero multiplicity form of f :: a -> b is just f :: forall (x :: a). b, because Haskell is wholesale type-erased in a way that Idris and other dependently typed languages cannot easily be. (In this sense, IMO, I think Haskell has the whole dependent type erasure problem that other languages have such trouble with neatly solved—at the cost of having to use an awkward encoding for everything else about dependent types!)
In the latter sense, the "dependent" Haskell (i.e. souped-up with singletons) way to take a dependent, unrestricted argument is this:
-- vvvvvv + vvvvvvvv duplicate information!
vecLen :: SNat n -> Vect n a -> SNat n
vecLen n _ = n -- allowed, ergh!
and the "zero multiplicity" version is just
vecLen :: Vect n a -> SNat n
-- must walk Vect, cannot match on erased types like n
vecLen Nil = SZ
vecLen (_ `Cons` xs) = SS (goodLen xs)

Besides as-pattern, what else can # mean in Haskell?

I am studying Haskell currently and try to understand a project that uses Haskell to implement cryptographic algorithms. After reading Learn You a Haskell for Great Good online, I begin to understand the code in that project. Then I found I am stuck at the following code with the "#" symbol:
-- | Generate an #n#-dimensional secret key over #rq#.
genKey :: forall rq rnd n . (MonadRandom rnd, Random rq, Reflects n Int)
=> rnd (PRFKey n rq)
genKey = fmap Key $ randomMtx 1 $ value #n
Here the randomMtx is defined as follows:
-- | A random matrix having a given number of rows and columns.
randomMtx :: (MonadRandom rnd, Random a) => Int -> Int -> rnd (Matrix a)
randomMtx r c = M.fromList r c <$> replicateM (r*c) getRandom
And PRFKey is defined below:
-- | A PRF secret key of dimension #n# over ring #a#.
newtype PRFKey n a = Key { key :: Matrix a }
All information sources I can find say that # is the as-pattern, but this piece of code is apparently not that case. I have checked the online tutorial, blogs and even the Haskell 2010 language report at https://www.haskell.org/definition/haskell2010.pdf. There is simply no answer to this question.
More code snippets can be found in this project using # in this way too:
-- | Generate public parameters (\( \mathbf{A}_0 \) and \(
-- \mathbf{A}_1 \)) for #n#-dimensional secret keys over a ring #rq#
-- for gadget indicated by #gad#.
genParams :: forall gad rq rnd n .
(MonadRandom rnd, Random rq, Reflects n Int, Gadget gad rq)
=> rnd (PRFParams n gad rq)
genParams = let len = length $ gadget #gad #rq
n = value #n
in Params <$> (randomMtx n (n*len)) <*> (randomMtx n (n*len))
I deeply appreciate any help on this.
That #n is an advanced feature of modern Haskell, which is usually not covered by tutorials like LYAH, nor can be found the the Report.
It's called a type application and is a GHC language extension. To understand it, consider this simple polymorphic function
dup :: forall a . a -> (a, a)
dup x = (x, x)
Intuitively calling dup works as follows:
the caller chooses a type a
the caller chooses a value x of the previously chosen type a
dup then answers with a value of type (a,a)
In a sense, dup takes two arguments: the type a and the value x :: a. However, GHC is usually able to infer the type a (e.g. from x, or from the context where we are using dup), so we usually pass only one argument to dup, namely x. For instance, we have
dup True :: (Bool, Bool)
dup "hello" :: (String, String)
...
Now, what if we want to pass a explicitly? Well, in that case we can turn on the TypeApplications extension, and write
dup #Bool True :: (Bool, Bool)
dup #String "hello" :: (String, String)
...
Note the #... arguments carrying types (not values). Those are something that exists at compile time, only -- at runtime the argument does not exist.
Why do we want that? Well, sometimes there is no x around, and we want to prod the compiler to choose the right a. E.g.
dup #Bool :: Bool -> (Bool, Bool)
dup #String :: String -> (String, String)
...
Type applications are often useful in combination with some other extensions which make type inference unfeasible for GHC, like ambiguous types or type families. I won't discuss those, but you can simply understand that sometimes you really need to help the compiler, especially when using powerful type-level features.
Now, about your specific case. I don't have all the details, I don't know the library, but it's very likely that your n represents a kind of natural-number value at the type level. Here we are diving in rather advanced extensions, like the above-mentioned ones plus DataKinds, maybe GADTs, and some typeclass machinery. While I can't explain everything, hopefully I can provide some basic insight. Intuitively,
foo :: forall n . some type using n
takes as argument #n, a kind-of compile-time natural, which is not passed at runtime. Instead,
foo :: forall n . C n => some type using n
takes #n (compile-time), together with a proof that n satisfies constraint C n. The latter is a run-time argument, which might expose the actual value of n. Indeed, in your case, I guess you have something vaguely resembling
value :: forall n . Reflects n Int => Int
which essentially allows the code to bring the type-level natural to the term-level, essentially accessing the "type" as a "value". (The above type is considered an "ambiguous" one, by the way -- you really need #n to disambiguate.)
Finally: why should one want to pass n at the type level if we then later on convert that to the term level? Wouldn't be easier to simply write out functions like
foo :: Int -> ...
foo n ... = ... use n
instead of the more cumbersome
foo :: forall n . Reflects n Int => ...
foo ... = ... use (value #n)
The honest answer is: yes, it would be easier. However, having n at the type level allows the compiler to perform more static checks. For instance, you might want a type to represent "integers modulo n", and allow adding those. Having
data Mod = Mod Int -- Int modulo some n
foo :: Int -> Mod -> Mod -> Mod
foo n (Mod x) (Mod y) = Mod ((x+y) `mod` n)
works, but there is no check that x and y are of the same modulus. We might add apples and oranges, if we are not careful. We could instead write
data Mod n = Mod Int -- Int modulo n
foo :: Int -> Mod n -> Mod n -> Mod n
foo n (Mod x) (Mod y) = Mod ((x+y) `mod` n)
which is better, but still allows to call foo 5 x y even when n is not 5. Not good. Instead,
data Mod n = Mod Int -- Int modulo n
-- a lot of type machinery omitted here
foo :: forall n . SomeConstraint n => Mod n -> Mod n -> Mod n
foo (Mod x) (Mod y) = Mod ((x+y) `mod` (value #n))
prevents things to go wrong. The compiler statically checks everything. The code is harder to use, yes, but in a sense making it harder to use is the whole point: we want to make it impossible for the user to try adding something of the wrong modulus.
Concluding: these are very advanced extensions. If you're a beginner, you will need to slowly progress towards these techniques. Don't be discouraged if you can't grasp them after only a short study, it does take some time. Make a small step at a time, solve some exercises for each feature to understand the point of it. And you'll always have StackOverflow when you are stuck :-)

Using State Monad turns all of my functions into monadic functions

I write a cryptography library in Haskell to learn about cryptography and monads. (Not for real-world use!) The type of my function for primality testing is
prime :: (Integral a, Random a, RandomGen g) => a -> State g Bool
So as you can see I use the State Monad so I don't have the thread through the generator all the time. Internally the prime function uses the Miller-Rabin test, which rely on random numbers, which is why the prime function also must rely on random number. It makes sense in a way since the prime function only does a probabilistic test.
Just for reference, the entire prime function is below, but I don't think you need to read it.
-- | findDS n, for odd n, gives odd d and s >= 0 s.t. n=2^s*d.
findDS :: Integral a => a -> (a, a)
findDS n = findDS' (n-1) 0
where
findDS' q s
| even q = findDS' (q `div` 2) (s+1)
| odd q = (q,s)
-- | millerRabinOnce n d s a does one MR round test on
-- n using a.
millerRabinOnce :: Integral a => a -> a -> a -> a -> Bool
millerRabinOnce n d s a
| even n = False
| otherwise = not (test1 && test2)
where
(d,s) = findDS n
test1 = powerModulo a d n /= 1
test2 = and $ map (\t -> powerModulo a ((2^t)*d) n /= n-1)
[0..s-1]
-- | millerRabin k n does k MR rounds testing n for primality.
millerRabin :: (RandomGen g, Random a, Integral a) =>
a -> a -> State g Bool
millerRabin k n = millerRabin' k
where
(d, s) = findDS n
millerRabin' 0 = return True
millerRabin' k = do
rest <- millerRabin' $ k - 1
test <- randomR_st (1, n - 1)
let this = millerRabinOnce n d s test
return $ this && rest
-- | primeK k n. Probabilistic primality test of n
-- using k Miller-Rabin rounds.
primeK :: (Integral a, Random a, RandomGen g) =>
a -> a -> State g Bool
primeK k n
| n < 2 = return False
| n == 2 || n == 3 = return True
| otherwise = millerRabin (min n k) n
-- | Probabilistic primality test with 64 Miller-Rabin rounds.
prime :: (Integral a, Random a, RandomGen g) =>
a -> State g Bool
prime = primeK 64
The thing is, everywhere I need to use prime numbers, I have to turn that function into a monadic function too. Even where it's seemingly not any randomness involved. For example, below is my former function for recovering a secret in Shamir's Secret Sharing Scheme. A deterministic operation, right?
recover :: Integral a => [a] -> [a] -> a -> a
recover pi_s si_s q = sum prods `mod` q
where
bi_s = map (beta pi_s q) pi_s
prods = zipWith (*) bi_s si_s
Well that was when I used a naive, deterministic primality test function. I haven't rewritten the recover function yet, but I already know that the beta function relies on prime numbers, and hence it, and recover too, will. And both will have to go from simple non-monadic functions into two monadic function, even though the reason they use the State Monad / randomness is really deep down.
I can't help but think that all the code becomes more complex now that it has to be monadic. Am I missing something or is this always the case in situations like these in Haskell?
One solution I could think of is
prime' n = runState (prime n) (mkStdGen 123)
and use prime' instead. This solution raises two questions.
Is this a bad idea? I don't think it's very elegant.
Where should this "cut" from monadic to non-monadic code be? Because I also have functions like this genPrime:
_
genPrime :: (RandomGen g, Random a, Integral a) => a -> State g a
genPrime b = do
n <- randomR_st (2^(b-1),2^b-1)
ps <- filterM prime [n..]
return $ head ps
The question becomes whether to have the "cut" before or after genPrime and the like.
That is indeed a valid criticism of monads as they are implemented in Haskell. I don't see a better solution on the short term than what you mention, and switching all the code to monadic style is probably the most robust one, even though they are more heavyweight than the natural style, and indeed it can be a pain to port a large codebase, although it may pay off later if you want to add more external effects.
I think algebraic effects can solve this elegantly, for examples:
eff (example program with randomness)
F*
All functions are annotated with their effects a -> eff b, however, contrary to Haskell, they can all be composed simply like pure functions a -> b (which are thus a special case of effectful functions, with an empty effect signature). The language then ensures that effects form a semi-lattice so that functions with different effects can be composed.
It seems difficult to have such a system in Haskell. Free(r) monads libraries allow composing types of effects in a similar way, but still require the explicit monadic style at the term level.
One interesting idea would be to overload function application, so it can be implicitly changed to (>>=), but a principled way to do so eludes me. The main issue is that a function a -> m b is seen as both an effectful function with effects in m and codomain b, and as a pure function with codomain m b. How can we infer when to use ($) or (>>=)?
In the particular case of randomness, I once had a somewhat related idea involving splittable random generators (shameless plug): https://blog.poisson.chat/posts/2017-03-04-splittable-generators.html

Haskell type family instance with type constraints

I am trying to represent expressions with type families, but I cannot seem to figure out how to write the constraints that I want, and I'm starting to feel like it's just not possible. Here is my code:
class Evaluable c where
type Return c :: *
evaluate :: c -> Return c
data Negate n = Negate n
instance (Evaluable n, Return n ~ Int) => Evaluable (Negate n) where
type Return (Negate n) = Return n
evaluate (Negate n) = negate (evaluate n)
This all compiles fine, but it doesn't express exactly what I want. In the constraints of the Negate instance of Evaluable, I say that the return type of the expression inside Negate must be an Int (with Return n ~ Int) so that I can call negate on it, but that is too restrictive. The return type actually only needs to be an instance of the Num type class which has the negate function. That way Doubles, Integers, or any other instance of Num could also be negated and not just Ints. But I can't just write
Return n ~ Num
instead because Num is a type class and Return n is a type. I also cannot put
Num (Return n)
instead because Return n is a type not a type variable.
Is what I'm trying to do even possible with Haskell? If not, should it be, or am I misunderstanding some theory behind it? I feel like Java could add a constraint like this. Let me know if this question could be clearer.
Edit: Thanks guys, the responses are helping and are getting at what I suspected. It appears that the type checker isn't able to handle what I'd like to do without UndecidableInstances, so my question is, is what I'd like to express really undecidable? It is to the Haskell compiler, but is it in general? i.e. could a constraint even exist that means "check that Return n is an instance of Num" which is decidable to a more advanced type checker?
Actually, you can do exactly what you mentioned:
{-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances #-}
class Evaluable c where
type Return c :: *
evaluate :: c -> Return c
data Negate n = Negate n
instance (Evaluable n, Num (Return n)) => Evaluable (Negate n) where
type Return (Negate n) = Return n
evaluate (Negate n) = negate (evaluate n)
Return n certainly is a type, which can be an instance of a class just like Int can. Your confusion might be about what can be the argument of a constraint. The answer is "anything with the correct kind". The kind of Int is *, as is the kind of Return n. Num has kind * -> Constraint, so anything of kind * can be its argument. It perfectly legal (though vacuous) to write Num Int as a constraint, in the same way that Num (a :: *) is legal.
To complement Eric's answer, let me suggest one possible alternative: using a functional dependency instead of a type family:
class EvaluableFD r c | c -> r where
evaluate :: c -> r
data Negate n = Negate n
instance (EvaluableFD r n, Num r) => EvaluableFD r (Negate n) where
evaluate (Negate n) = negate (evaluate n)
This makes it a bit easier to talk about the result type, I think. For instance, you can write
foo :: EvaluableFD Int a => Negate a -> Int
foo x = evaluate x + 12
You can also use ConstraintKinds to apply this partially (which is why I put the arguments in that funny-looking order):
type GivesInt = EvaluableFD Int
You could do this with your class as well, but it would be more annoying:
type GivesInt x = (Evaluable x, Result x ~ Int)

Trying to make my typeclass/instance. GHC says "Could not deduce..."

I am trying to make a simple graph structure and I wrote the following. But GHG raises error and I stacked there. This is the first time I make my own typeclass so maybe I am doing something terribly wrong. Can somebody explain what is wrong?
I found a similar question but I don't think it applies to my case.:
Error binding type variables in instance of typeclass
class Link l where
node :: (Node n) => l -> n
class Node n where
links :: (Link l) => n -> [l]
data (Node n) => SimpleLink n =
SimpleLink
{ simpleLinkNode :: n
} deriving (Show, Read, Eq)
instance (Node n) => Link (SimpleLink n) where
node = simpleLinkNode
data (Link l) => SimpleNode l =
SimpleNode
{ simpleNodeLinks :: [l]
} deriving (Show, Read, Eq)
instance (Link l) => Node (SimpleNode l) where
links = simpleNodeLinks
This is the error message I've got:
***.hs:13:10:Could not deduce (n ~ n1)
from the context (Node n)
bound by the instance declaration
at ***.hs:12:10-40
or from (Node n1)
bound by the type signature for
node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3-23
`n' is a rigid type variable bound by
the instance declaration
at ***.hs:12:16
`n1' is a rigid type variable bound by
the type signature for node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3
Expected type: SimpleLink n -> n1
Actual type: SimpleLink n -> n
In the expression: simpleLinkNode
In an equation for `node': node = simpleLinkNode
***.hs:21:11:Could not deduce (l ~ l1)
from the context (Link l)
bound by the instance declaration
at ***.hs:20:10-40
or from (Link l1)
bound by the type signature for
links :: Link l1 => SimpleNode l -> [l1]
at ***.hs:21:3-25
`l' is a rigid type variable bound by
the instance declaration
at ***.hs:20:16
`l1' is a rigid type variable bound by
the type signature for links :: Link l1 => SimpleNode l -> [l1]
at ***.hs:21:3
Expected type: SimpleNode l -> [l1]
Actual type: SimpleNode l -> [l]
In the expression: simpleNodeLinks
In an equation for `links': links = simpleNodeLinks
Edit 1
I tried some of Daniel's suggestions.
But I couldn't make them work.
constructor class
Got: "`n' is not applied to enough type arguments"
class Link l n where
node :: Node n l => l n -> n l
class Node n l where
links :: Link l n => n l -> [l n]
multi-parameter type class (MPTC)
Got: "Cycle in class declarations (via superclasses)"
class (Node n) => Link l n where
node :: l -> n
class (Link l) => Node n l where
links :: n -> [l]
MPTC with functional dependencies
Got: "Cycle in class declarations (via superclasses)"
class (Node n) => Link l n | l -> n where
node :: l -> n
class (Link l) => Node n l | n -> l where
links :: n -> [l]
Goal (Edit 2)
What I want to implement is a directed acyclic graph structure like the following (more specifically, a Factor graph).
(source: microsoft.com)
There are two kinds of node (white circle and red square) and they connect only to the different type of node, meaning that there are two kinds of links.
I want different version of nodes and links which have data (arrays) attached to them. I also want "vanilla" DAG which has only one type of node and link. But for traversing them, I want only one interface to do that.
The signature of the class methods
class Link l where
node :: (Node n) => l -> n
class Node n where
links :: (Link l) => n -> [l]
say that "whatever type the caller desires, node resp. links can produce it, as long as it's a member of Link resp. Node", but the implementation says that only one specific type of value can be produced.
It's fundamentally different from interfaces in OOP, where the implementation decides the type and the caller has to take it, here the caller decides.
You are running into kind problems with your constructor class attempt. Your classes take two parameters, l of kind kl and n of kind kn. The kinds of the arguments to (->) must both be *, the kind of types. So for l n to be a well-kinded argument of (->), l must be a type constructor taking an argument of kind kn and creating a result of kind *, i.e.
l :: kn -> *
Now you try to make the result type of node be n l, so that would mean
n :: kl -> *
But above we saw that kl = kn -> *, which yields
n :: (kn -> *) -> *
resp. kn = (kn -> *) -> *, which is an infinite kind. Infinite kinds, like infinite types, are not allowed. But kind-inference is implemented only very rudimentary, so the compiler assumes that the argument to l has kind *, but sees from n l that n has kind kl -> *, hence as an argument to l, n has the wrong kind, it is not applied to enough type arguments.
The normal use of constructor classes is a single-parameter class
class Link l where
node :: l nod -> nod
class Node n where
links :: n lin -> [lin]
-- note that we don't have constraints here, because the kinds don't fit
instance Link SimpleLink where
node = simpleLinkNode
instance Node SimpleNode where
links = simpleNodeLinks
You have to remove the DatatypeContexts from the data declarations,
They have been removed from the language (they are available via an extension)
They were never useful anyway
then the above compiles. I don't think it would help you, though. As Chris Kuklewicz observed, your types chase their own tail, you'd use them as
SimpleLink (SimpleNode (SimpleLink (SimpleNode ... {- ad infinitum -})))
For the multiparameter classes, you can't have each a requirement of the other, as the compiler says, that causes a dependency cycle (also, in your constraints you use them with only one parameter,
class Node n => Link l n where ...
which is malformed, the compiler would refuse that if the cycle is broken).
You could resolve the cycle by merging the classes,
class NodeLinks l n | l -> n, n -> l where
node :: l -> n
links :: n -> l
but you'd still have the problems that your types aren't useful for that.
I don't understand your goal well enough to suggest a viable solution, sorry.
Can somebody explain what is wrong?
An initial issue before I explain the error messages: Polymorphic data types are good, but in the end there has to be concrete type being used.
With SimpleNode of kind * -> * and SimpleLinks of kind * -> * there is no concrete type:
SimpleNode (SimpleLink (SimpleNode (SimpleLink (SimpleNode (...
You cannot have and infinite type in Haskell, though newtype and data get you closer:
type G0 = SimpleNode (SimpleLink G0) -- illegal
newtype G1 = G1 (SimpleNode (SimpleLink G1)) -- legal
data G2 = G2 (SimpleNode (SimpleLink G2)) -- legal
Perhaps you need to rethink your data types before creating the type class.
Now on to the error message explanation: Your type class Link defines a function node
class Link l where
node :: (Node n) => l -> n
The node is a magical OOP factory that, given the type and value of l, can then make any type n (bounded by Node n) the caller of node wishes. This n has nothing to do with the n in your instance:
instance (Node n) => Link (SimpleLink n) where
node = simpleLinkNode
To repeat myself: the n in the instance above is not the same n as in the node :: (Node n) => l -> n definition. The compiler makes a related but fresh name n1 and gives you the error:
`n' is a rigid type variable bound by
the instance declaration
at ***.hs:12:16
`n1' is a rigid type variable bound by
the type signature for node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3
The n in the instance is taken from the type (SimpleLink n) of the input to the node function. The n1 is the type that the caller of node is demanding that this magical factory produce. If n and n1 were the same then the compiler would be happy...but your definition of the type class and instance do not constrain this and thus the code snippet is rejected.
The analogous story is repeated for the error in SimpleLink. There is no silver-bullet fix for this. I expect that you need to rethink and redesign this, probably after reading other people's code in order to learn ways to accomplish your goal.
What is your goal? Graph data structures can be quite varied and the details matter.
I am breaking stack overflow etiquette and adding a second answer to keep this separate. This is a simple code example for a bipartite undirected graph with unlabeled edges, which might be useful to model a Factor Graph:
-- Bipartite graph representation, unlabeled edges
-- Data types to hold information about nodes, e.g. ID number
data VariableVertex = VV { vvID :: Int } deriving (Show)
data FactorVertex = FV { fvID :: Int } deriving (Show)
-- Node holds itself and a list of neighbors of the oppostite type
data Node selfType adjacentType =
N { self :: selfType
, adj :: [Node adjacentType selfType] }
-- A custom Show for Node to prevent infinite output
instance (Show a, Show b) => Show (Node a b) where
show (N x ys) = "Node "++ show x ++ " near " ++ show (map self ys)
-- Type aliases for the two node types that will be used
type VariableNode = Node VariableVertex FactorVertex
type FactorNode = Node FactorVertex VariableVertex
data FactorGraph = FG [VariableNode] [FactorNode] deriving (Show)
v1 = N (VV 1) [f1,f2]
v2 = N (VV 2) [f2]
v3 = N (VV 3) [f1,f3]
f1 = N (FV 1) [v1,v3]
f2 = N (FV 2) [v1,v2]
f3 = N (FV 3) [v3]
g = FG [v1,v2,v3] [f1,f2,f3]
With the hint from Chris Kuklewicz (http://stackoverflow.com/a/11450715/727827), I got the code I wanted in the first place.
However, I think Crhis's answer (using *Vertex to hold data) is simple and better. I am leaving this here to clarify what I wanted.
class NodeClass n where
adjacent :: n a b -> [n b a]
data Node selfType adjacentType =
N
{ selfNode :: selfType
, adjNode :: [Node adjacentType selfType] }
data NodeWithData selfType adjacentType =
NWD
{ selfNodeWithData :: selfType
, adjNodeWithData :: [NodeWithData adjacentType selfType]
, getDataWithData :: [Double]
}
instance NodeClass Node where
adjacent = adjNode
instance NodeClass NodeWithData where
adjacent = adjNodeWithData
data VariableVertex = VV { vvID :: Int } deriving (Show)
data FactorVertex = FV { fvID :: Int } deriving (Show)
type VariableNode = Node VariableVertex FactorVertex
type FactorNode = Node FactorVertex VariableVertex
type VariableNodeWithData = NodeWithData VariableVertex FactorVertex
type FactorNodeWithData = NodeWithData FactorVertex VariableVertex

Resources