edwardw
edwardw

Reputation: 13992

Is there a type 'Any' in haskell?

Say, I want to define a record Attribute like this:

data Attribute = Attribute {name :: String, value :: Any}

This is not valid haskell code of course. But is there a type 'Any' which basically say any type will do? Or is to use type variable the only way?

data Attribute a = Attribute {name :: String, value :: a}

Upvotes: 48

Views: 14362

Answers (6)

Fidel
Fidel

Reputation: 41

Daniel Wagner response is the right one: almost in 90% of cases using a polymorphic type is all that you need. All the other responses are useful for the remaining 10% of cases, but if you have still no good knowledge of polymorphism as to ask this question, it will be extremely complicated to understand GADTs or Existential Types... My advice is "keep it as simple as possible".

Upvotes: 0

Edgar Klerks
Edgar Klerks

Reputation: 1537

If your data needs to be eventually a specific type, You could use Convertible with GADTs. Because as consumer, you are only interested in a the datatype you need to consume.

{-# LANGUAGE GADTs #-}
import Data.Convertible 

data Conv b where 
   Conv ::  a -> (a -> b) -> Conv b
   Chain :: Conv b -> (b -> c) -> Conv c

unconv :: (Conv b) -> b 
unconv (Conv a f) = f a
unconv (Chain c f) = f $ unconv c

conv :: Convertible a b => a -> Conv b 
conv a = (Conv a convert)

totype :: Convertible b c => Conv b -> Conv c
totype a = Chain a convert

It is not very difficult to derive functor, comonad and monad instances for this. I can post them if you are interested.

Upvotes: 2

Mikhail Glushenkov
Mikhail Glushenkov

Reputation: 15058

Adding to bdonlan's answer: Instead of GADTs, you can also use existential types:

{-# LANGUAGE ExistentialQuantification #-}

class Foo a where
  foo :: a -> a

data AnyFoo = forall a. Foo a => AnyFoo a

instance Foo AnyFoo where
  foo (AnyFoo a) = AnyFoo $ foo a

mapFoo :: [AnyFoo] -> [AnyFoo]
mapFoo = map foo

This is basically equivalent to bdonlan's GADT solution, but doesn't impose the choice of data structure on you - you can use a Map instead of a list, for example:

import qualified Data.Map as M

mFoo :: M.Map String AnyFoo
mFoo = M.fromList [("a", AnyFoo SomeFoo), ("b", AnyFoo SomeBar)]

The data AnyFoo = forall a. Foo a => AnyFoo a bit can also be written in GADT notation as:

data AnyFoo where
  AnyFoo :: Foo a => a -> AnyFoo

Upvotes: 25

bdonlan
bdonlan

Reputation: 231223

Generally speaking, Any types aren't very useful. Consider: If you make a polymorphic list that can hold anything, what can you do with the types in the list? The answer, of course, is nothing - you have no guarantee that there is any operation common to these elements.

What one will typically do is either:

  1. Use GADTs to make a list that can contain elements of a specific typeclass, as in:

    data FooWrap where
        FooWrap :: Foo a => a -> FooWrap
    type FooList = [FooWrap]
    

    With this approach, you don't know the concrete type of the elements, but you know they can be manipulated using elements of the Foo typeclass.

  2. Create a type to switch between specific concrete types contained in the list:

    data FooElem = ElemFoo Foo | ElemBar Bar
    type FooList = [FooElem]
    

    This can be combined with approach 1 to create a list that can hold elements that are of one of a fixed set of typeclasses.

  3. In some cases, it can be helpful to build a list of manipulation functions:

    type FooList = [Int -> IO ()]
    

    This is useful for things like event notification systems. At the time of adding an element to the list, you bind it up in a function that performs whatever manipulation you'll later want to do.

  4. Use Data.Dynamic (not recommended!) as a cheat. However, this provides no guarantee that a specific element can be manipulated at all, and so the above approaches should be preferred.

Upvotes: 75

Daniel Wagner
Daniel Wagner

Reputation: 152937

This sounds like a pretty basic question, so I'm going to give an even more basic answer than anybody else. Here's what is almost always the right solution:

data Attribute a = Attribute { name :: String, value :: a }

Then, if you want an attribute that wraps an Int, that attribute would have type Attribute Int, or an attribute that wraps a Bool would have type Attribute Bool, etc. You can create these attributes with values of any type; for example, we can write

testAttr = Attribute { name = "this is only a test", value = Node 3 [] }

to create a value of type Attribute (Tree Int).

Upvotes: 15

augustss
augustss

Reputation: 23014

There is the type Dynamic from Data.Dynamic which can hold anything (well, anything Typeable). But that is rarely the right way to do it. What is the problem that you are trying to solve?

Upvotes: 14

Related Questions