Alias for datatypes in Haskell - haskell

So I've got a structure like this:
data Maybe a = Nothing | Just a
but I want a structure that is defined as
data MaybeInt = Nothing | Just Int
is there a way to define MaybeInt using Maybe a, and if so how?

There are a few ways to define MaybeInt. I'll state them then have some commentary.
Direct
data MaybeInt = NothingInt | JustInt Int
Newtype
newtype MaybeInt = MI (Maybe Int)
Type synonym
type MaybeInt = Maybe Int
Plain
-- just use `(Maybe Int)` wherever you would write `MaybeInt`
Commentary
Most commonly, one would use the plain method since most people are familiar with Maybe and thus know to use Just and Nothing to match it. This makes it good for libraries—very transparent. The type synonym method is a common documentation method, but is basically useless for your synonym. It makes it so that foo :: Int -> Maybe Int and bar :: Int -> MaybeInt have identical type signatures. It also means that as soon as someone knows that MaybeInt === Maybe Int they can use the Just/Nothing constructors for matching.
The newtype method gets fairly interesting. Here you have to begin "wrapping" and "unwrapping" the MI constructor every time you want to use the MaybeInt type. Compare:
baz :: MaybeInt -> Bool
baz (MI Nothing) = False
baz (MI (Just int)) = True
this is nice because if you don't export MI then nobody will be able to match on MaybeInt (despite having a pretty good guess at what's going on inside of it). This is really useful for making stable APIs. Another interesting property of newtype is that you can write new instances for MaybeInt which are different from Maybe's built-in ones. For instance, you could override the Monoid instance
instance Monoid MaybeInt where
mempty = MI Nothing
mi `mappend` (MI Nothing) = mi
_ `mappend` mi = mi
which is just the same as the Last a newtype built-in to Data.Monoid which wraps Maybe as.
Finally, we get the full-blown data instance. It's more verbose, more likely to error, marginally slower (since the compiler has to track a new, unique data type), and requires that people learn new constructors. For functionality so obviously identical to Maybe Int there's really no reason to use it at all.

Related

Writing modules in Haskell the right way

(I'm totally rewriting this question to give it a better focus; you can see the history of changes if you want to see the original.)
Let's say I have two modules:
One module defines the function inverseAndSqrt. What this function actually does is not important; what is important is that it returns none, one, or both of two things in a way that the client can distinguish which one is which;
module Module1 (inverseAndSqrt) where
type TwoOpts a = (Maybe a, Maybe a)
inverseAndSqrt :: Int -> TwoOpts Float
inverseAndSqrt x = (if x /= 0 then Just (1.0/(fromIntegral x)) else Nothing,
if x >= 0 then Just (sqrt $ fromIntegral x) else Nothing)
another module defines other functions depending on inverseAndSqrt and on its type
module Module2 where
import Module1
fun :: (Maybe Float, Maybe Float) -> Float
fun (Just x, Just y) = x + y
fun (Just x, Nothing) = x
fun (Nothing, Just y) = y
exportedFun :: Int -> Float
exportedFun = fun . inverseAndSqrt
What I want to understand from the perspective of design principle is: how should I interface Module1 with other modules (e.g. Module2) in a way that makes it well encapsulated, reusable, etc?
The problems I see are
I could one day decide that I don't want to use a pair to return the two results anymore; I could decide to use a 2 elements list; or another type which is isomorphic (I think this is the right adjective, isn't it?) to a pair; if I do this, all client code will break
Exporting the TwoOpts type synonym doesn't solve anything, as Module1 could still change its implementation thus breaking client code.
Module1 is also forcing the type of the two optionals to be the same, but I'm not sure this is really relevant to this question...
How should I design Module1 (and thus edit Module2 as well) such that the two are not tightly coupled?
One thing I can think of is that maybe I should define a typeclass expressing what "a box with two optional things in it" is, and then Module1 and Module2 would use that as a common interface. But should that be in both module? In either of them? Or in none of them, in a third module? Or maybe such a class/concept is not needed?
I'm not a computer scientist so I'm sure that this question highlights some misunderstanding of mine due to lack of experience and theoretical background. Any help filling the gaps is welcome.
Possible modifications I'd like to support
Related to what chepner suggested in a comment to his answer, at some point I might want to extend the support from 2-tuple things to both 2- and 3-tuple things, having different accessor names for them, suche as get1of2/get2of2 (let's say these are the name we use when we first design Module1) vs get1of3/get2of3/get3of3.
At some point I would also be able to complement this 2-tuple-like type with something else, for instance an optional containing Just the sum¹ of the two main contents only if they are both Justs, or a Nothing if at least one of the two main contents is a Nothing. I guess in this case the internal representation of this class would be something like ((Maybe a, Maybe a), Maybe b) (¹ The sum is really a stupid example, so I've used b here instead of a to be more general than the sum would require).
To me, Haskell design is all type-centric. The design rule for functions is just "use the most general and accurate types that do the job", and the whole problem of design in Haskell is about coming up with the best types for the job.
We would like there to be no "junk" in the types, so that they have exactly one representation for each value you want to denote. E.g. String is a bad representation for numbers, because "0", "0.0", "-0" all mean the same thing, and also because "The Prisoner" is not a number -- it is a valid representation that does not have a valid denotation. If, say for performance reasons, the same denotation can be represented multiple ways, the type's API should make that difference invisible to the user.
So in your case, (Maybe a, Maybe a) is perfect -- it means exactly what you need it to mean. Using something more complicated is unnecessary, and will just complicate matters for the user. At some point whatever you expose will have to be convertible to a Maybe a for the first thing and a Maybe a for the second thing, and there is no extra information than that, so the tuple is perfect. Whether you use a type synonym or not is a matter of style -- I prefer not use synonyms at all and only give types names when I have a more formal abstraction in mind.
Connotation is important. For example, if I had a function for finding the roots of a quadratic polynomial, I probably wouldn't use TwoOpts, even though there are at most two of them. The fact that my return values are all "the same kind of thing" in an intuitive sense makes me prefer a list (or if I'm feeling particularly picky, a Set or Bag), even if the list has at most two elements. I just have it match my best understanding of the domain at the time, so I won't change it unless my understanding of the domain has changed in a significant way, in which case the opportunity to review all its uses is exactly what I want. If you are writing your functions to be as polymorphic as possible, then often you won't need to change anything but the specific moments the meaning is used, the exact moment domain knowledge is required (such as understanding the relationship between TwoOpts and Set). You don't need to "redo the plumbing" if it's made of a sufficiently flexible, polymorphic material.
Supposing you didn't have a clean isomorphism to a standard type like (Maybe a, Maybe a), and you wanted to formalize TwoOpts. The way here is to build an API out of its constructors, combinators, and eliminators. For example:
data TwoOpts a -- abstract, not exposed
-- constructors
none :: TwoOpts a
justLeft :: a -> TwoOpts a
justRight :: a -> TwoOpts a
both :: a -> a -> TwoOpts a
-- combinators
-- Semigroup and Monoid at least
swap :: TwoOpts a -> TwoOpts a
-- eliminators
getLeft :: TwoOpts a -> Maybe a
getRight :: TwoOpts a -> Maybe a
In this case the eliminators give exactly your representation (Maybe a, Maybe a) as their final coalgebra.
-- same as the tuple in a newtype, just more conventional
data TwoOpts a = TwoOpts (Maybe a) (Maybe a)
Or if you wanted to focus on the constructors side you could use an initial algebra
data TwoOpts a
= None
| JustLeft a
| JustRight a
| Both a a
You are at liberty to change this representation as long as it still implements the combinatory API above. If you have reason to use different representations of the same API, make the API into a typeclass (typeclass design is a whole other story).
In Einstein's famous words, "make it as simple as possible, but no simpler".
Don't define a simple type alias; this exposes the details of how you implement TwoOpts.
Instead, define a new type, but don't export the data constructor, but rather functions for accessing the two components. Then you are free to change the implementation of the type all you like without changing the interface, because the user can't pattern-match on a value of type TwoOpts a.
module Module1 (TwoOpts, inverseAndSqrt, getFirstOpt, getSecondOpt) where
data TwoOpts a = TwoOpts (Maybe a) (Maybe a)
getFirstOpt, getSecondOpt :: TwoOpts a -> Maybe a
getFirstOpt (TwoOpts a _) = a
getSecondOpt (TwoOpts _ b) = b
inverseAndSqrt :: Int -> TwoOpts Float
inverseAndSqrt x = TwoOpts (safeInverse x) (safeSqrt x)
where safeInverse 0 = Nothing
safeInverse x = Just (1.0 / fromIntegral x)
safeSqrt x | x >= 0 = Just $ sqrt $ fromIntegral x
| otherwise = Nothing
and
module Module2 where
import Module1
fun :: TwoOpts Float -> Float
fun a = case (getFirstOpts a, getSecondOpt a) of
(Just x, Just y) -> x + y
(Just x, Nothing) -> x
(Nothing, Just y) -> y
exportedFun :: Int -> Float
exportedFun = fun . inverseAndSqrt
Later, when you realize that you've reimplemented the type product, you can change your definitions without affecting any user code.
newtype TwoOpts a = TwoOpts { getOpts :: (Maybe a, Maybe a) }
getFirstOpt, getSecondOpt :: TwoOpts a -> Maybe a
getFirstOpt = fst . getOpts
getSecondOpt = snd . getOpts

Safest way to generate random GADT with Hedgehog (or any other property-based testing framework)

I have GADT like this one:
data TType a where
TInt :: TType Int
TBool :: TType Bool
I want to have a function like this one:
genTType :: Gen (TType a)
Which can generate random constructor of TType type. I can do this simply by creating existentially qualified data type like
data AnyType = forall a . MkAnyType (TType a)
then generate random number from 0 to 1 (including) and create AnyType depending on the integer value. Like this:
intToAnyType :: Int -> AnyType
intToAnyType 0 = MkAnyType TInt
intToAnyType 1 = MkAnyType TBool
intToAnyType _ = error "Impossible happened"
But this approach has couple drawbacks to me:
No external type safety. If I add another constructor to TType data type I can forgot to fix tests and compiler won't warn me about this.
Compiler can't stop me from writing intToAnyType 1 = MkAnyType TInt.
I don't like this error. Int type is too broad to me. It would be nice to make this pattern-matching exhaustive.
What can I do in Haskell to eliminate as much as possible drawbacks here? Preferably using generators from this module:
https://hackage.haskell.org/package/hedgehog-0.5.1/docs/Hedgehog-Gen.html
Generating genTType with Template Haskell is probably your best bet to automate maintenance of the generators, because there is no generic programming support for GADTs.
For your last point, instead of generating an integer and then mapping it to a value, use oneof or element.
element [MkAnyType TInt, MkAnyType TBool]

Use of 'unsafeCoerce'

In Haskell, there is a function called unsafeCoerce, that turns anything into any other type of thing. What exactly is this used for? Like, why we would you want to transform things into each other in such an "unsafe" way?
Provide an example of a way that unsafeCoerce is actually used. A link to Hackage would help. Example code in someones question would not.
unsafeCoerce lets you convince the type system of whatever property you like. It's thus only "safe" exactly when you can be completely certain that the property you're declaring is true. So, for instance:
unsafeCoerce True :: Int
is a violation and can lead to wonky, bad runtime behavior.
unsafeCoerce (3 :: Int) :: Int
is (obviously) fine and will not lead to runtime misbehavior.
So what's a non-trivial use of unsafeCoerce? Let's say we've got an typeclass-bound existential type
module MyClass ( SomethingMyClass (..), intSomething ) where
class MyClass x where {}
instance MyClass Int where {}
data SomethingMyClass = forall a. MyClass a => SomethingMyClass a
Let's also say, as noted here, that the typeclass MyClass is not exported and thus nobody else can ever create instances of it. Indeed, Int is the only thing that instantiates it and the only thing that ever will.
Now when we pattern match to destruct a value of SomethingMyClass we'll be able to pull a "something" out from inside
foo :: SomethingMyClass -> ...
foo (SomethingMyClass a) =
-- here we have a value `a` with type `exists a . MyClass a => a`
--
-- this is totally useless since `MyClass` doesn't even have any
-- methods for us to use!
...
Now, at this point, as the comment suggests, the value we've pulled out has no type information—it's been "forgotten" by the existential context. It could be absolutely anything which instantiates MyClass.
Of course, in this very particular situation we know that the only thing implementing MyClass is Int. So our value a must actually have type Int. We could never convince the typechecker that this is true, but due to an outside proof we know that it is.
Therefore, we can (very carefully)
intSomething :: SomethingMyClass -> Int
intSomething (SomethingMyClass a) = unsafeCoerce a -- shudder!
Now, hopefully I've suggested that this is a terrible, dangerous idea, but it also may give a taste of what kind of information we can take advantage of in order to know things that the typechecker cannot.
In non-pathological situations, this is rare. Even rarer is a situation where using something we know and the typechecker doesn't isn't itself pathological. In the above example, we must be completely certain that nobody ever extends our MyClass module to instantiate more types to MyClass otherwise our use of unsafeCoerce becomes instantly unsafe.
> instance MyClass Bool where {}
> intSomething (SomethingMyClass True)
6917529027658597398
Looks like our compiler internals are leaking!
A more common example where this sort of behavior might be valuable is when using newtype wrappers. It's a fairly common idea that we might wrap a type in a newtype wrapper in order to specialize its instance definitions.
For example, Int does not have a Monoid definition because there are two natural monoids over Ints: sums and products. Instead, we use newtype wrappers to be more explicit.
newtype Sum a = Sum { getSum :: a }
instance Num a => Monoid (Sum a) where
mempty = Sum 0
mappend (Sum a) (Sum b) = Sum (a+b)
Now, normally the compiler is pretty smart and recognizes that it can eliminate all of those Sum constructors in order to produce more efficient code. Sadly, there are times when it cannot, especially in highly polymorphic situations.
If you (a) know that some type a is actually just a newtype-wrapped b and (b) know that the compiler is incapable of deducing this itself, then you might want to do
unsafeCoerce (x :: a) :: b
for a slight efficiency gain. This, for instance, occurs frequently in lens and is expressed in the Data.Profunctor.Unsafe module of profunctors, a dependency of lens.
But let me again suggest that you really need to know what's going on before using unsafeCoerce like this is anything but highly unsafe.
One final thing to compare is the "typesafe cast" available in Data.Typeable. This function looks a bit like unsafeCoerce, but with much more ceremony.
unsafeCoerce :: a -> b
cast :: (Typeable a, Typeable b) => a -> Maybe b
Which, you might think of as being implemented using unsafeCoerce and a function typeOf :: Typeable a => a -> TypeRep where TypeRep are unforgeable, runtime tokens which reflect the type of a value. Then we have
cast :: (Typeable a, Typeable b) => a -> Maybe b
cast a = if (typeOf a == typeOf b) then Just b else Nothing
where b = unsafeCoerce a
Thus, cast is able to ensure that the types of a and b really are the same at runtime, and it can decide to return Nothing if they are not. As an example:
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ExistentialQuantification #-}
data A = A deriving (Show, Typeable)
data B = B deriving (Show, Typeable)
data Forget = forall a . Typeable a => Forget a
getAnA :: Forget -> Maybe A
getAnA (Forget something) = cast something
which we can run as follows
> getAnA (Forget A)
Just A
> getAnA (Forget B)
Nothing
So if we compare this usage of cast with unsafeCoerce we see that it can achieve some of the same functionality. In particular, it allows us to rediscover information that may have been forgotten by ExistentialQuantification. However, cast manually checks the types at runtime to ensure that they are truly the same and thus cannot be used unsafely. To do this, it demands that both the source and target types allow for runtime reflection of their types via the Typeable class.
The only time I ever felt compelled to use unsafeCoerce was on finite natural numbers.
{-# LANGUAGE DataKinds, GADTs, TypeFamilies, StandaloneDeriving #-}
data Nat = Z | S Nat deriving (Eq, Show)
data Fin (n :: Nat) :: * where
FZ :: Fin (S n)
FS :: Fin n -> Fin (S n)
deriving instance Show (Fin n)
Fin n is a singly linked data structure that is statically ensured to be smaller than the n type level natural number by which it is parametrized.
-- OK, 1 < 2
validFin :: Fin (S (S Z))
validFin = FS FZ
-- type error, 2 < 2 is false
invalidFin :: Fin (S (S Z))
invalidFin = FS (FS FZ)
Fin can be used to safely index into various data structures. It's pretty standard in dependently typed languages, though not in Haskell.
Sometimes we want to convert a value of Fin n to Fin m where m is greater than n.
relaxFin :: Fin n -> Fin (S n)
relaxFin FZ = FZ
relaxFin (FS n) = FS (relaxFin n)
relaxFin is a no-op by definition, but traversing the value is still required for the types to check out. So we might just use unsafeCoerce instead of relaxFin. More pronounced gains in speed can result from coercing larger data structures that contain Fin-s (for example, you could have lambda terms with Fin-s as bound variables).
This is an admittedly exotic example, but I find it interesting in the sense that it's pretty safe: I can't really think of ways for external libraries or safe user code to mess this up. I might be wrong though and I'd be eager to hear about potential safety issues.
There is no use of unsafeCoerce I can really recommend, but I can see that in some cases such a thing might be useful.
The first use that springs to mind is the implementation of the Typeable-related routines. In particular cast :: (Typeable a, Typeable b) => a -> Maybe b achieves a type-safe behaviour, so it is safe to use, yet it has to play dirty tricks in its implementation.
Maybe unsafeCoerce can find some use when importing FFI subroutines to force types to match. After all, FFI already allows to import impure C functions as pure ones, so it is intrinsecally usafe. Note that "unsafe" does not mean impossible to use, but just "putting the burden of proof on the programmer".
Finally, pretend that sortBy did not exist. Consider then this example:
-- Like Int, but using the opposite ordering
newtype Rev = Rev { unRev :: Int }
instance Ord Rev where compare (Rev x) (Rev y) = compare y x
sortDescending :: [Int] -> [Int]
sortDescending = map unRev . sort . map Rev
The code above works, but feels silly IMHO. We perform two maps using functions such as Rev,unRev which we know to be no-ops at runtime. So we just scan the list twice for no reason, but that of convincing the compiler to use the right Ord instance.
The performance impact of these maps should be small since we also sort the list. Yet it is tempting to rewrite map Rev as unsafeCoerce :: [Int]->[Rev] and save some time.
Note that having a coercing function
castNewtype :: IsNewtype t1 t2 => f t2 -> f t1
where the constraint means that t1 is a newtype for t2 would help, but it would be quite dangerous. Consider
castNewtype :: Data.Set Int -> Data.Set Rev
The above would cause the data structure invariant to break, since we are changing the ordering underneath! Since Data.Set is implemented as a binary search tree, it would cause quite a large damage.

Why does Haskell not have records with structural typing?

I have heard Haskell described as having structural typing. Records are an exception to that though as I understand. For example foo cannot be called with something of type HRec2 even though HRec and HRec2 are only nominally different in their fields.
data HRec = HRec { x :: Int, y :: Bool }
data HRec2 = HRec2 { p :: Int, q :: Bool }
foo :: HRec -> Bool
Is there some explanation for rejecting extending structural typing to everything including records?
Are there statically typed languages with structural typing even for records? Is there maybe some debate on this I can read about for all statically typed languages in general?
Haskell has structured types, but not structural typing, and that's not likely to change.*
The refusal to permit nominally different but structurally similar types as interchangeable arguments is called type safety. It's a good thing. Haskell even has a newtype declaration to provide types which are only nominally different, to allow you to enforce more type safety. Type safety is an easy way to catch bugs early rather than permit them at runtime.
In addition to amindfv's good answer which includes ad hoc polymorphism via typeclasses (effectively a programmer-declared feature equivalence), there's parametric polymorphism where you allow absolutely any type, so [a] allows any type in your list and BTree a allows any type in your binary tree.
This gives three answers to "are these types interchangeable?".
No; the programmer didn't say so.
Equivalent for a specific purpose because the programmer said so.
Don't care - I can do the same thing to this collection of data because it doesn't use any property of the data itself.
There's no 4: compiler overrules programmer because they happened to use a couple of Ints and a String like in that other function.
*I said Haskell is unlikely to change to structural typing. There is some discussion to introduce some form of extensible records, but no plans to make (Int,(Int,Int)) count as the same as (Int, Int, Int) or Triple {one::Int, two::Int, three::Int} the same as Triple2 {one2::Int, two2::Int, three2::Int}.
Haskell records aren't really "less structural" than the rest of the type system. Every type is either completely specified, or "specifically vague" (i.e. defined with a typeclass).
To allow both HRec and HRec2 to f, you have a couple of options:
Algebraic types:
Here, you define HRec and HRec2 records to both be part of the HRec type:
data HRec = HRec { x :: Int, y :: Bool }
| HRec2 { p :: Int, q :: Bool }
foo :: HRec -> Bool
(alternately, and maybe more idiomatic:)
data HRecType = Type1 | Type2
data HRec = HRec { hRecType :: HRecType, x :: Int, y :: Bool }
Typeclasses
Here, you define foo as able to accept any type as input, as long as a typeclass instance has been written for that type:
data HRec = HRec { x :: Int, y :: Bool }
data HRec2 = HRec2 { p :: Int, q :: Bool }
class Flexible a where
foo :: a -> Bool
instance Flexible HRec where
foo (HRec a _) = a == 5 -- or whatever
instance Flexible HRec2 where
foo (HRec2 a _) = a == 5
Using typeclasses allows you to go further than regular structural typing -- you can accept types that have the necessary information embedded in them, even if the types don't superficially look similar, e.g.:
data Foo = Foo { a :: String, b :: Float }
data Bar = Bar { c :: String, d :: Integer }
class Thing a where
doAThing :: a -> Bool
instance Thing Foo where
doAThing (Foo x y) = (x == "hi") && (y == 0)
instance Thing Bar where
doAThing (Bar x y) = (x == "hi") && ((fromInteger y) == 0)
We can run fromInteger (or any arbitrary function) to get the data we need from what we have!
I'm aware of two library implementations of structurally typed records in Haskell:
HList is older, and is explained in an excellent paper: Haskell's overlooked object system (free online, but SO won't let me include more links)
vinyl is newer, and uses fancy new GHC features. There's at least one library, vinyl-gl, using it.
I cannot answer the language-design part of your question, though.
To answer your last question, Go and Scalas definitely have structural typing. Some people (including me) would call that "statically unsafe typing", since it implicitly declares all samely- named methods in a program to have the same semantics, which implies "spooky action at a distance", relating code in on source file to code in some library that the program has never seen.
IMO, better to require that the same-named methods to explicitly declare that they conform to a named semantic "model" of behavior.
Yes, the compiler would guarantee that the method is callable, but it isn't much safer than saying:
f :: [a] -> Int
And letting the compiler choose an arbitrary implementation that may or may not be length.
(A similar idea can be made safe with Scala "implicits" or Haskell (GHC?) "reflection" package.)

Are there "type-level combinators"? Will they exist in some future?

Much of what makes haskell really nice to use in my opinion are combinators such as (.), flip, $ <*> and etc. It feels almost like I can create new syntax when I need to.
Some time ago I was doing something where it would be tremendously convenient if I could "flip" a type constructor. Suppose I have some type constructor:
m :: * -> * -> *
and that I have a class MyClass that needs a type with a type constructor with kind * -> *. Naturally I would choose to code the type in such a way that I can do:
instance MyClass (m a)
But suppose I can't change that code, and suppose that what really fits into MyClass is something like
type w b = m b a
instance MyClass w where
...
and then I'd have to activate XTypeSynonymInstances. Is there some way to create a "type level combinator" Flip such that I can just do:
instance MyClass (Flip m a) where
...
?? Or other type level generalisations of common operators we use in haskell? Is this even useful or am I just rambling?
Edit:
I could do something like:
newtype Flip m a b = Flip (m b a)
newtype Dot m w a = Dot m (w a)
...
But then I'd have to use the data constructors Flip, Dot, ... around for pattern matching and etc. Is it worth it?
Your question makes sense, but the answer is: no, it's not currently possible.
The problem is that (in GHC Haskell's type system) you can't have lambdas at the type level. For anything you might try that looks like it could emulate or achieve the effect of a type level lambda, you will discover that it doesn't work. (I know, because I did.)
What you can do is declare your Flip newtypes, and then write instances of the classes you want for them, painfully with the wrapping and the unwrapping (by the way: use record syntax), and then clients of the classes can use the newtypes in type signatures and not have to worry about the details.
I'm not a type theorist and I don't know the details of why exactly we can't have type level lambdas. I think it was something to do with type inference becoming impossible, but again, I don't really know.
You can do the following, but I don't think its actually very useful, since you still can't really partially apply it:
{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
module Main where
class TFlip a where
type FlipT a
instance TFlip (f a b) where
type FlipT (f a b) = f b a
-- *Main> :t (undefined :: FlipT (Either String Int))
-- (undefined :: FlipT (Either String Int)) :: Either Int [Char]
Also see this previous discussion: Lambda for type expressions in Haskell?
I'm writing answer here just for clarifying things and to tell about achievements in the last years. There're a lot of features in Haskell and now you can write some operators in type. Using $ you can write something like this:
foo :: Int -> Either String $ Maybe $ Maybe Int
to avoid parenthesis instead of good old
foo :: Int -> Either String (Maybe (Maybe Int))

Resources