How to define a family of type dependent function in Haskell - haskell

This is a (series of) Haskell question(s). I am fairly new to Haskell.
Suppose we have a 4-tuple (a1,a2,a3,a4). How do we define a function, kth, that gives the k-th element in this tuple? Example,
kth (1,"A",'b',True) 3 = 'b'
If the types of a1, a2, a3, a4 are the same, then it has a fairly simple definition. For example, if they are all integers:
kth :: (Int,Int,Int,Int) -> Int -> Int
kth (a1,a2,a3,a4) 1 = a1
kth (a1,a2,a3,a4) 2 = a2
kth (a1,a2,a3,a4) 3 = a3
kth (a1,a2,a3,a4) 4 = a4
My suspicion of why this is not straightforward is because Haskell must know the type in advance. In the library function fst and snd, Haskell knows that the output type is the type of the first element for the formal, and the output type is the type of the second element for the latter. Hence, there is no ambiguity. In kth, the output type depends on the second input, hence Haskell cannot do type check based on the syntax.
Now, suppose we have a n-th tuple (a1,a2,...,an). Can we define a family of length functions such that
lengthTuple :: a -> Int
lengthTuple (a1,a2,...,an) = n

This kind of problem (dependent type) is still a headache in Haskell. The Tuple from Prelude is not quite suitable for this kind of task (perhaps doable though). But you can use the sized vector with dependent type for this kind of problem.
Example:
https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell

You can not implement your function if the index must be an Int, but you could if that were a custom "singleton" index type. Essentially, if we want to mimic dependent types, the best option we have is to pass singletons around a lot, to connect type-level values to term-level ones.
Here is one example:
{-# LANGUAGE GADTs, DataKinds, TypeFamilies #-}
{-# OPTIONS -Wall #-}
-- custom index type
data Ix = I1 | I2 | I3 | I4
-- associated singleton type (this could be autogenerated using the singletons library)
data SIx (ix :: Ix) where
SI1 :: SIx 'I1
SI2 :: SIx 'I2
SI3 :: SIx 'I3
SI4 :: SIx 'I4
-- type level function
type family T (ix :: Ix) a1 a2 a3 a4
type instance T 'I1 a1 _ _ _ = a1
type instance T 'I2 _ a2 _ _ = a2
type instance T 'I3 _ _ a3 _ = a3
type instance T 'I4 _ _ _ a4 = a4
-- our "dependent" tuple selector
choose :: (a1, a2, a3, a4) -> SIx ix -> T ix a1 a2 a3 a4
choose (x1, _, _, _) SI1 = x1
choose (_, x2, _, _) SI2 = x2
choose (_, _, x3, _) SI3 = x3
choose (_, _, _, x4) SI4 = x4
If wanted, we can "hide" the ix parameter of SIx ix and T ix a1 a2 a3 a4 using an existential wrapper (as a sort of dependent sum type), building a function that given "some index" returns "some component".
This would be much more convenient if we had real dependent types. Still, this is the price we currently pay to have type erasure at runtime. If Haskell one day adds non-erased pi a . ... types to the erased ones forall a . ... we have now, we will have much more control.

The short answer, as suggested in some comments, is that you shouldn't seriously be doing this in Haskell. If you find yourself needing to write functions that can operate on differently sized tuples, you're programming Haskell wrong.
However, the idiomatic method of defining a function like lengthTuple is to use type classes with explicit instances for different tuple sizes. If this is for a library, you pick some upper bound and write instances up to that size. A reasonable choice might be a 15-tuple, since that's also the largest tuple that has a Show instance:
> (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
> (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
<interactive>:72:1: error:
• No instance for (Show ...
So, the definition for lengthTuple would look like this:
class Tuple a where lengthTuple :: a -> Int
instance Tuple (a,b) where lengthTuple _ = 2
instance Tuple (a,b,c) where lengthTuple _ = 3
instance Tuple (a,b,c,d) where lengthTuple _ = 4
...up to 15...
Tedious, but pretty standard.
Remarkably, it is possible to write lengthTuple without any boilerplate using Data.Data generics. These generics provide a way to fold over the structure of an algebraic data type in a fairly general way, and you can use a Const functor to ignore the actual content of the data type while counting the number of fields:
import Data.Data
import Data.Functor.Const
lengthTuple :: (Data a) => a -> Int
lengthTuple = getConst . gfoldl (\(Const n) _ -> Const (n+1))
(\_ -> Const 0)
This works fine, though there's no straightforward way to restrict it to tuples, and you may find its return value for non-tuples somewhat surprising:
> lengthTuple (1,2,3,4)
4
> lengthTuple ""
0
> lengthTuple "what the heck?"
2
Writing kth is much, much harder. Your intuition is right. Because the type of the expression kth tuple n depends on the value rather than the type of the parameter n, a simple definition isn't possible. The other answers have covered a couple of approaches.

Related

Accessing a common field in sum type variants

Suppose I have a sum type (or several, in fact), that I know by design all have a common field:
data T1 a
= C1 String a
| C2 Int a
| C3 Bool a
data T2 a
= C4 Int Int a
| C5 [String] a
Is there a way to access the a field without having to pattern match on all variants across all types?
(I ask in the context of defining ASTs & having a neat way of accessing node-specific information)
A Minor Technical Detail
At the boring super-technical level, no. There is no way to access the fields of a constructor without pattern matching. Pattern matching is the primitive operation that causes the constructor to be evaluated. Before that, the fields don't even necessarily exist (thanks to non-strict evaluation).
Some Options That Might Be Useful
But you probably didn't mean that low-level question. You probably want a way to work with these data types without constantly writing pattern matches. And that can be done. It's just a matter of writing some functions. Which functions, though? ...that can be interesting.
You can write simple accessor functions:
t1ToA :: T1 a -> a
t1ToA (C1 _ x) = x
t1ToA (C2 _ x) = x
t1ToA (C3 _ x) = x
t2ToA :: T2 a -> a
t2ToA (C4 _ _ x) = x
t2ToA (C5 _ x) = x
Don't automatically reject this approach. Sure, it's a bit hungry on namespace because you need a different function name for each type. On the other hand, it's really good for readability and type inference. There's nothing magical anywhere. You might write some matching setter and modifier functions as well.
If you find that's getting to be too namespace hungry when you have various set and modify functions added in, you could use the van Laarhoven trick:
t1A :: Functor f => (a -> f a) -> T1 a -> f (T1 a)
t1A g (C1 x y) = C1 x <$> g y
t1A g (C2 x y) = C2 x <$> g y
t1A g (C3 x y) = C3 x <$> g y
t2A :: Functor f => (a -> f a) -> T2 a -> f (T2 a)
t2A g (C4 x y z) = C4 x y <$> g z
t2A g (C5 x y) = C5 x <$> g y
This representation lets you do reading and updating from the same type, though it is awkward without some helper functions. This is the representation used by libraries like lens, which provide you a huge number of those helper functions. But maybe you don't want to worry about learning how to work with this representation. I'm going to assume this isn't really what you're looking for and not even go into the details of how those helper functions work. But at a high level, they make clever use of specific types for f like Identity and Const a.
An option if you are willing to give up some type inference in order to reduce namespace use is to go for some sort of ad-hoc class:
class ToA f where
toA :: f a -> a
instance ToA T1 where
toA (C1 _ x) = x
toA (C2 _ x) = x
toA (C3 _ x) = x
instance ToA T2 where
toA :: T2 a -> a
toA (C4 _ _ x) = x
toA (C5 _ x) = x
You could choose to combine this with the van Laarhoven encoding, for what it's worth. This would minimize the amount of namespace you grab, but requiring some additional helpers for the sake of using them easily.
There are a few other options that you might be able to work with, like using less ad-hoc tools GHC provides. Data and Generic are different classes you could work with where GHC gives you a lot of the tools already. But these tend to be very complex to pick up the first time around.
But Maybe There's a Better Solution
There's one last option that is actually the one I would recommend in most cases. Refactor your data types so the shared values aren't duplicated.
data WithA t a = WithA t a
data T1
= C1 String
| C2 Int
| C3 Bool
And so on. Or however you might choose to refactor it. The important part is that the shared field is lifted out of the sum type, and is just always present. I think that this often ends up working the best. It often communicates what you mean better. When you have 3 constructors which each have a field of the same type it's not immediately obvious that that field should be seen as interchangeable between the constructors, even when the datatype is polymorphic over that field's type. But if it's a single field outside of the multiple constructors it is immediately obvious that it's always the same thing. Don't underestimate the communication value that provides for all future maintainers of the code.
Carl already mentioned a few alternatives. For completeness, let me add that using records allows one to use a common field name for all constructors, and that in turn allows to get/set the common field.
data T a
= K1 { foo :: a, oth1 :: Int }
| K2 { foo :: a, oth2 :: String }
get :: T a -> a
get = foo
set :: T a -> a -> T a
set t x = t{foo = x}
I am not a huge fan of this approach since other fields like oth1, oth2 become partial functions. I would rather refactor the type as Carl showed (the WithA example).

a way to simulate Union types without type operators

I have done this before using type operators, but I want to exclude those because I want to be able to do it with a smaller hammer, because I actually want to do it in another language, and I'm not too sure type operators do quite what I want.
The setup is two data types, Integer and...
> data Rational = Rational Integer Integer deriving Show
two type classes with sensible instances...
> class Divide2 a where
> divide2 :: a -> a
> class Increment a where
> inc :: a -> a
> instance Increment Main.Rational where
> inc (Rational a b) = Rational (a + b) b
> instance Divide2 Main.Rational where
> divide2 (Rational a b) = Rational a (2 * b)
> instance Increment Integer where
> inc x = x + 1
I can define things that work instances of one type class or the other
> div4 x = divide2 (divide2 x)
> add2 :: Increment c => c -> c
> add2 = inc . inc
and then I want to take the union of these two data types...so the obvious thing to do is use a discriminated
> data Number = Rat Main.Rational | Int Integer
now...in my scenario, the functions that act on this union, exist in one distinct module (a binary, I'm not familiar with Haskells binaries)
but the data types themselves are defined in another
So clearly I can define some functions that (in principle) can potentially "work" on this union, e.g. functions that act on values of instances of Increment....and some that don't, e.g. one in Divide2
So how do I write a function, against this discriminated union, that applys a function to values in the union, that will compile for functions on Increment, but don't compile on functions on Divide2...I'll have a go here, and fall flat on my face.
> apply (Rat r) f = f r
> apply (Int i) f = f i
.
• Couldn't match expected type ‘Main.Rational’
with actual type ‘Integer’
• In the first argument of ‘f’, namely ‘i’
In the expression: f i
In an equation for ‘apply’: apply (Int i) f = f i
|
86 | > apply (Int i) f = f i | ^
Failed, no modules loaded.
as expected, the inference says its got to be an Rational because of the first call, but its an Integer...
but "clearly"...if I could make haskell suspect disbelief...like some sort of macro...then the function
> apply (Int 1) add2
does make sense, and moreover, makes sense for any value of Number I care to choose.
so the obvious thing to do is to make Number a member of anything in the intersection of the set of type classes each member is in....
> instance Increment Number where
> inc (Rat r) = inc (Rat r)
> inc (Int i) = inc (Int i)
and then ghc implements "apply" itself...I CAN as well map this solution back into other languages by some explicit dictionary passing...but I have hundreds, if not thousands of tiny typeclasses (I may even have to consider all their combinations as well).
so really I want to know is there some type magic (existential? rankn?) that means that I CAN write "apply" against Number, without resorting to some dependent type magic, or have to implement instances of type classes on the discriminated union.
P.S. I can do limited dependent type magic...but its a last resort,
Edit...
The code that contains the functions defined on Number can of course match the disciminated values, but if they do, then whenever union is extended, they will fail to compile (ok, they don't have to match each case individally, but unless they do, they can't extract the wrapped value to apply the function, because it wont know the type)
Hmmm...written down it looks like the expression problem, in fact it IS the expression problem...I know of many solutions then...I just don't usually like any of them...let me knock up the canonical Haskell solution to this using type classes.
You can accept only functions that make use of Increment methods (and do not make use of any non-Incremental functionality) like this:
{-# LANGUAGE RankNTypes #-}
apply :: (forall a. Increment a => a -> a) -> Number -> Number
apply f (Rat r) = Rat (f r)
apply f (Int i) = Int (f i)
You can now pass add2 to apply if you like:
> apply add2 (Rat (Rational 3 4))
Rat (Rational 11 4)
In this specific case, implementing apply amounts to exactly the same thing as supplying an Increment instance for Number itself:
instance Increment Number where
inc (Rat r) = Rat (inc r)
inc (Int i) = Int (inc i)
...and now you don't even need the mediating apply function to apply add2:
> add2 (Rat (Rational 3 4))
Rat (Rational 11 4)
But this is a pretty special case; it won't always be so easy to just implement the appropriate classes for Number, and you will need to resort to something like the higher-rank types we used in apply instead.
So this IS the expression problem, so type classes solve this specific case.
you take the function you want to make general over some as yet undefined universe of types
> class Add2 a where
> add2' :: a -> a
> newtype Number' a = Number' a
> instance (Increment a) => Add2 (Number' a) where
> add2' (Number' x) = Number' $ inc (inc x)
> three = add2 (Int 1)
and then make any type that inhabits the required preconditions in terms of type classes, inhabit the typeclass for your generalised "function".
you then implement your new "Number" data types, and create instances of them where they make sense.

Anonymous records: what ways to type-level tag in Haskell?

I'm playing with lightweight anonymous record-alikes, more to explore the type theory for them than anything 'industrial strength'. I want the fields to be simply type-tagged.
myRec = (EmpId 54321, EmpName "Jo", EmpPhone "98-7654321") -- in which
newtype EmpPhone a = EmpPhone a -- and maybe
data EmpName a where EmpName :: IsString a => a -> EmpName a -- GADT
data EmpId a where EmpId :: Int -> EmpId Int -- GADT to same pattern
Although I could put newtype EmpId = EmpId Int, I want to follow the same pattern for all tags, so that I can go for example:
project (EmpId, EmpName) myRec -- use tags as field names
I'll also use StandaloneDeriving/DeriveAnyType to derive instance Eq, Show, Num etc.
Other possible designs
For the records, rather than Haskell tuples I could use HList or make my own data types Tuple0, Tuple1, Tuple2, .... I don't think that would affect the typing issues below.
For the tags/fields I could pair a Symbol (type-level String) as phantom type with the value -- for example CTRex does something like that. Then use TypeApplications to build fields.
data Tag (tag :: Symbol) a = Tag a
myRec = (Tag #"EmpId" 54321, ...)
That makes the field syntax (and projection list) rather 'noisy'; also prevents any validation that EmpIds are Int, etc.
Three related lines of questions on typing for these:
How best to prevent
sillyRec = (EmpId 65432, Just "not my tag", "or [] as constructor",
Right "or even worse" :: Either Int String)
I could declare a class, put my tags only in it (not too bad with DeriveAnyClass), put constraints everywhere. But my tags have a consistent structure: single data constructor named same as the type; single type parameter which is the only parameter to the data constructor.
How to express I want each record-alike to follow a consistent type pattern? That is prevent:
notaRec = (EmpId 76543, EmpName)
Bare EmpName is OK in a projection list, providing all the other fields are bare constructors. I want to say that notaRec is not well-Kinded, but bare EmpName is Kind * -> *, which is unifiable with *. So I mean more like: all fields in the record fit the same type pattern.
Then when I get to sets-of-records (aka tables/relations)
myTable = ( myRec, -- tuple of tuples
(EmpName "Kaz", EmpPhone 987654312, EmpId 87654),
EmpId 98765, EmpPhone "21-4365879", EmpName "Bo")
Putting the fields in a different order is OK because we have a tuple-of-tuples. But EmpPhone is at two different types in the two records. And the last line isn't a record at all: it's fields at the 'wrong' pattern. (Same mis-match as with bare EmpName in 2.)
Again I want to say these are ill-Kinded. My field tags are appearing at different 'depths' or in differing type patterns.
I guess I could get there with a great deal of hard-coding for valid instances/combos of types. Is there a more generic way?
EDIT: In response to comments. (Yes I'm mortal too. Thanks #duplode for figuring out the formatting.)
why not type Record = (EmpId Int, EmpName String, EmpPhone String)?
As a type synonym that's fine. But doesn't answer the question because I want it equivalent to any permutation of those tags. (I think I can verify that equivalence at type level using HList techniques.)
some sort of high-level overview of your objective [thank you David]
I want to treat the ( ... , ... , ... ) as a set. Because the Relational Database Model says relations are sets of 'tuples' [not Haskell tuples] and 'tuples' are sets of pairs of tag-value. I also want to treat the project function as having a first-class parameter which is a set of tags. (Contrast that in Codd's Relational Algebra, the π operator has its set of tags subscripted as if part of the operator.)
These couldn't be Haskell Sets because the elements are not the same type. I want to say the elements are the same Kind; and that a Haskell-tuple of same-Kinded elements represents a set-of that Kind. But I know that's abusing terminology. (The alternative design I considered using Symbol tags perhaps shows better there's a Kindiness aspect.)
If I can treat the Haskell tuples as set-ish, I can use well-known HList techniques to emulate the Relational Operators.
If this helps explain, I could do this with a lot of boilerplate:
class MyTag a -- type/kind-level predicate
deriving instance MyTag (EmpId Int) -- uses DeriveAnyClass
-- etc for all my tags
class WellKinded tup
instance WellKinded ()
instance {-# OVERLAPPING #-}
(MyTag (n1 a1), MyTag (n2 a2), MyTag (n3 a3))
=> WellKinded (n1 a1, n2 a2, n3 a3) -- and so on for every arity of tuple
instance {-# OVERLAPPABLE #-}
(MyTag (n1 a1), MyTag (n2 a2), MyTag (n3 a3))
=> WellKinded (a1 -> n1 a1, a2 -> n2 a2, a3 -> n3 a3)
All those instances for different arities are rapidly going to get tedious, so I could convert to HList; despatch an instance on the Kind of the first element; iterate down the list verifying all the same Kind.
For tuple-of-tuples, detect the Kind of the first element of the first sub-tuple; iterate both across and down. (Again needs OverlappingInstances: a tuple-of-tuples-of-tuples is still a tuple. This is what I mean by "a great deal of hard-coding" above.) It doesn't seem unachievable. But it does feel like going down the wrong rabbit-hole.
This is crazy enough it might just work. Pattern synonyms to the rescue:
newtype Label (n :: Symbol) (a :: *) = MkLab a -- newtype yay!
deriving (Eq, Ord, Show)
pattern EmpPhone x = MkLab x :: Label "EmpPhone" a
pattern EmpName x = MkLab x :: IsString a => Label "EmpName" a
pattern EmpId x = MkLab x :: Label "EmpId" Int
myRec = (EmpId 54321, EmpName "Jo", EmpPhone "98-7654321") -- works a treat
Then to answer the q's
To count as a record, all tuple elements must be of type Label s a.
To count as a projection list, all tuple elements must be of type a -> Label s a.
(That works, by the way.)
Those are the only types/kinds allowed in tuples-as-records.
So to parse a tuple-of-tuples at type level, I need only despatch on the type of the leftmost element.
I'm looking for type constructor Label.
All the rest I can do with HList-style type matching.
For those patterns I did need to switch on a swag of extensions:
{-# LANGUAGE PatternSynonyms,
KindSignatures, DataKinds,
ScopedTypeVariables, -- for the signatures on patterns
RankNTypes #-} -- for the signatures with contexts
import GHC.TypeLits -- for the Symbols
Here's a kinda answer or at least explanation for 2., 3.; a partial answer to 1.
How to express I want each record-alike to follow a consistent type pattern? That is prevent:
notaRec = (EmpId 76543, EmpName)
On the face of it EmpId 76543 matches type pattern (n a); whereas EmpName :: a -> (n a). But Hindley-Milner doesn't "match" simplistically like that, it uses unifiability. So all of these unify with (n a):
-- as `( n a )`
a -> (n a) -- as `( ((->) a) (n a) )`
(b, c) -- as `( (,) b ) c `
(b, c, d) -- as `( (,,) b c ) d ` -- etc for all larger Haskell tuples
[ a ], Maybe a -- as `( [] a )`, `( Maybe a )`
Either b c -- as `( (Either b) c )`
b -> (Either b c) -- as `( ((->) b) (Either b c) )` -- for example, bare `Left`
To disagree with myself on the abuse of terminology:
I want to say these are ill-Kinded. My field tags are appearing at different 'depths' ...
But I know that's abusing terminology.
Any type with a -> outermost constructor is at a different Kind vs one without. Either is at a different Kind vs EmpId, because it is different arity. Type unification builds the 'most general unifier', and that makes them appear same-Kinded.
For the purposes here we want the opposite of the mgu -- call it the 'maximally specific Kind', MaSK for short.
We can express it with a closed Type Family and lots of overlapping equations (so the order of them is critical). This can also catch the Prelude's constructors that shouldn't count:
type family MaSK ( a :: * ) where
-- presume the result is one from some pre-declared bunch of types
-- use that result to verify all 'elements' of a set are same-kinded
MaSK (_ -> _ _ _) = No -- e.g. bare `Left`
MaSK (_ -> [ _ ]) = No -- reject unwanted constructors
MaSK (_ -> Maybe _ ) = No -- ditto
MaSK (a' -> n a') = YesAsBareTag -- this we want
MaSK (_ -> _ _ ) = No --
MaSK (_ -> _ ) = No
MaSK ( _ , _ , _ , _ ) = YesAsSet -- etc for greater arities
MaSK ( _ , _ , _ ) = YesAsSet
MaSK ( _ , _ ) = YesAsSet
MaSK (_ _ _ ) = No -- too much arity, e.g. `Either b c`
MaSK [ _ ] = No -- reject unwanted constructors
MaSK (Maybe _) = No -- ditto
MaSK (n a) = YesAsTagValue -- this we want providing all the above eliminated
MaSK _ = No -- i.e. bare `Int, Bool, Char, ...`
Limitations: this approach can't check there's a single data constructor for the type, nor that other constructors for that type match the pattern, nor that the constructor is named same as the type, nor that the constructor might smuggle in existentially-quantified parameters. For that, go full metal generics.

Polymorphic return types and "rigid type variable" error in Haskell

There's a simple record Column v a which holds a Vector from the Data.Vector family (so that v can be Vector.Unboxed, just Vector etc), it's name and type (simple enum-like ADT SupportedTypes). I would like to be able to serialize it using the binary package. To do that, I try to define a Binary instance below.
Now put works fine, however when I try to define deserialization in the get function and want to set a specific type to the rawVector that is being returned based on the colType (U.Vector Int64 when it's PInt, U.Vector Double when it's PDouble etc) - I get this error message:
Couldn't match type v with U.Vector
v is a rigid type variable bound by the instance declaration at src/Quark/Base/Column.hs:75:10
Expected type: v a
Actual type: U.Vector Int64
error.
Is there a better way to achieve my goal - deserialize Vectors of different types based on the colType value or am I stuck with defining Binary instance for all possible Vector / primitive type combinations? Shouldn't be the case...
Somewhat new to Haskell and appreciate any help! Thanks!
{-# LANGUAGE OverloadedStrings, TransformListComp, RankNTypes,
TypeSynonymInstances, FlexibleInstances, OverloadedLists, DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts,
TypeFamilies, ScopedTypeVariables, InstanceSigs #-}
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Unboxed as U
data Column v a = Column {rawVector :: G.Vector v a => v a, colName :: Text, colType :: SupportedTypes }
instance (G.Vector v a, Binary (v a)) => Binary (Column v a) where
put Column {rawVector = vec, colName = cn, colType = ct} = do put (fromEnum ct) >> put cn >> put vec
get = do t <- get :: Get Int
nm <- get :: Get Text
let pt = toEnum t :: SupportedTypes
case pt of
PInt -> do vec <- get :: Get (U.Vector Int64)
return Column {rawVector = vec, colName = nm, colType = pt}
PDouble -> do vec <- get :: Get (U.Vector Double)
return Column {rawVector = vec, colName = nm, colType = pt}
UPDATED Thank you for all the answers below, some pretty good ideas! It's quite clear that what I want to do is impossible to achieve head-on - so that is my answer. But the other suggested solutions are a good reading in itself, thanks a bunch!
The type you are really trying to represent is
data Column v = Column (Either (v Int) (v Double))
but this representation may be unsatisfactory to you. So how do you write this type with the vector itself at the 'top level' of the constructor?
First, start with a representation of your sum (Either Int Double) at the type level, as opposed to the value level:
data IsSupportedType a where
TInt :: IsSupportedType Int
TDouble :: IsSupportedType Double
From here Column is actually quite simple:
data Column v a = Column (IsSupportedType a) (v a)
But you'll probably want a existentially quantified to use it how you want:
data Column v = forall a . Column (IsSupportedType a) (v a)
The binary instance is as follows:
instance (Binary (v Int), Binary (v Double)) => Binary (Column v) where
put (Column t v) = do
case t of
TInt -> put (0 :: Int) >> put v
TDouble -> put (1 :: Int) >> put v
get = do
t :: Int <- get
case t of
0 -> Column TInt <$> get
1 -> Column TDouble <$> get
Note that there is no inherent reliance in Vector here - v could really be anything.
The problem you're actually running into (or if you're not yet, that you will) is that you're trying to decide a resulting type from an input value. You cannot do that. At all. You could cleverly lock the result type in a box and throw away the key so the type appears to be normal from the outside, but then you cannot do anything much with it because you locked the type in a box and threw away the key. You can store extra information about it using GADTs and boxing it up with a type class instance, but even still this is not a great idea.
Your could make your life far easier here if you simply had two constructors for Column to reflect whether there was a vector of Ints or Doubles.
But really, don't do any of that. Just let the automatically derivable Binary instance deserialize any deserializable value into your vector for you.
data Column a = ... deriving (Binary)
Using the DeriveAnyClass extension that let's you derive any class that has a Generic implementation (which Binary has). Then just deserialize a Column Double or a Column Int when you need it.
As the comment says, you can simply not case on the type, and always call
vec <- get
return Column {rawVector = vec, colName = nm, colType = pt}
This fulfills your type signature properly. But note that colType is not useful to you here -- you have no way to enforce that it corresponds to the type within your vector, since it only exists at the value level. But that may be ok, and you may simply want to remove colType from your data structure altogether, since you can always derive it directly from the concrete type of a chosen in Column v a.
In fact, the constraint in the Column type isn't doing much good either, and I think it would be better to render it just as
data Column v a = Column {rawVector :: v a, colName :: Text}
Now you can just enforce the G.Vector constraint at call sites where necessary...

writing a function that accepts multiple input and has multiple outputs in haskell

whats the correct way to write a function that can accept different input's and have different outputs
for example i'm using hmatrix and
lets say i want to accept a Matrix or a Vector in my function, and the output can be a Matrix or a Vector depending on hte formula
where T in the below example can be a matrix or a vector , is maybe the right tool for this?
Myfunc ::(Matrix A, Matrix/Vector T) -> Maybe(Matrix/Vector T)
Update using either mentioned below here is one possible solution
Myfunc :: Maybe Matrix Double t -> (Either Vector Double a,Matrix Double a) -> Either (Matrix Double T,Vector Double T)
Take a look at how matrix multiplication and left-divide are implemented in the source code for HMatrix.
Essentially, they define a multi-parameter type class which tells the function how to behave for different inputs, and it has a functional dependency which tells it what output is appropriate. For example, for multiplication:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
-- |The class declaration 'Mul a b c' means "an 'a' multiplied by a 'b' returns
-- a 'c'". The functional dependency 'a b -> c' means that once 'a' and 'b' are
-- specified, 'c' is determined.
class Mul a b c | a b -> c where
-- | Matrix-matrix, matrix-vector, and vector-matrix products.
(<>) :: Product t => a t -> b t -> c t
-- |Matrix times matrix is another matrix, implemented using the matrix
-- multiplication function mXm
instance Mul Matrix Matrix Matrix where
(<>) = mXm
-- |Matrix times vector is a vector. The implementation converts the vector
-- to a matrix and uses the <> instance for matrix/matrix multiplication/
instance Mul Matrix Vector Vector where
(<>) m v = flatten $ m <> asColumn v
-- |Vector times matrix is a (row) vector.
instance Mul Vector Matrix Vector where
(<>) v m = flatten $ asRow v <> m
You could either have a look at Either (I know, it's a bad joke), or, if your function has a general meaning but different implementations on different data types, you could define a typeclass.
edit: I didn't add any further details because your question isn't completely clear to me
The question is what do you want to do with your input? For example if you want to do comparison then you can say input has to be of class Ord like this:
myFunc :: (Ord a) => a -> b
Another way would be to use Either, but in that case you can have only two different data types. For example
myFunc :: Either a b -> Either c d
can accept and return different types.
Another solution would be to use a list of lists [[a]]. Essentially a vector is a matrix with a single row.

Resources