Case between two unrelated types in Haskell - haskell

Is it possible to use case expression between two unrelated types in Haskell, like in this example (not working) code:
data A = A
data B = B
f x = case x of
A -> 1
B -> 2
main = do
print $ test A
return ()
I know I can use Either here, but this code is not meant to be used - I want to deeply learn the Haskell type system and see what could be done.

A and B are distinct types. If you want a function that can take values of multiple types, you need a typeclass.
data A = A
data B = B
class F a where
f :: a -> Int
instance F A where
f _ = 1
instance F B where
f _ = 2
main = do
print $ f A

No, this is not possible with a normal case statement, but you can hack this sort of thing using type classes:
data A = A
data B = B
class Test a where
test :: a -> Int
instance Test A where test = const 1
instance Test B where test = const 2
main = print $ test A
But you should only use this if it's really required, as it gets messy very soon and you end up with needing a lots of extensions to the type system (UndecidableInstances, OverlappingInstances, ...)

Rather than writing your own type class for f, you could use the Typeable
class which has some support by ghc. You don't need to use Dynamic here, but in
some cases it is needed.
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Dynamic
data A = A deriving (Typeable)
data B = B deriving (Typeable)
f x | Just A <- fromDynamic x = 1
| Just B <- fromDynamic x = 2
f2 x | Just A <- cast x = 1
| Just B <- cast x = 2
main = do
print $ f (toDyn A)
print $ f2 A

Related

How to avoid repetition when "factoring" a Haskell function into two functions with various intermediary types?

Consider the following Haskell code:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
import Data.Singletons.TH
singletons [d| data SimpleType = Aaa | Bbb | Ccc | Ddd
deriving (Read)
|]
-- each SimpleType value has an associated type
type family Parsed (t :: SimpleType) :: * where
Parsed Aaa = [Int]
Parsed Bbb = Maybe Int
Parsed Ccc = (Int, Int)
Parsed Ddd = Int
forth :: SSimpleType t -> Int -> Parsed t
forth SAaa x = [x,x*2,x*3]
forth SBbb x = Just x
forth SCcc x = (1337, x)
forth SDdd x = x
back :: SSimpleType t -> Parsed t -> Int
back SAaa [_, y, _] = y + 5
back SBbb (Just y) = y - 7
back SCcc (y1, y2) = y1 + y2
back SDdd y = y * 2
helper b = back b . forth b
go :: SimpleType -> Int -> Int
go Aaa = helper SAaa
go Bbb = helper SBbb
go Ccc = helper SCcc
go Ddd = helper SDdd
main = do
-- SimpleType value comes at run-time
val <- readLn
putStrLn $ show $ go val 100
Is it possible to avoid the repetition when go is defined? In other words, is there a way to write something like:
go val = helper (someMagicFunction val)
singletons do not have to be a part of the solution,
... but the idea that go is factored into forth and back with intermediary types dependent on Simple should be preserved.
You can use toSing from SingKind to convert a value of SimpelType to a value of SomeSing SimpleType, which is an existentially quantified wrapper around Sing SimpleType. You can then unwrap that value to get Sing SimpleType, which you can then pass to back and forth:
go :: SimpleType -> Int -> Int
go val x =
case toSing val of
SomeSing s -> back s $ forth s x
An instance of SingKind is generated for you (among many other things) by the singletons splice that you're using.
Note that, while a single-branch case is asking to be a let, this wouldn't compile:
go val x =
let (SomeSing s) = toSing val
in back s $ forth s x
This is prohibited, because let can be recursive, and since unwrapping a GADT may bring new types into context, it may result in creating an infinite type. A case branch, on the other hand, cannot be recursive, so this works. (credit for this explanation to #HTNW)
But a helper function would also work:
go val x = helper $ toSing val
where
helper (SomeSing s) = back s $ forth s x

Simpler syntax for overloading function names

In Haskell with the type families extension, this is perfectly legal (ideone):
{-# LANGUAGE TypeFamilies #-}
type family F a
data A = A Int
data B = B Double
type instance F A = Int
type instance F B = Double
class Get a where
get :: a -> F a
instance Get A where
get (A x) = x
instance Get B where
get (B x) = x
main = print $ (get (A 3), get (B 2.0))
Basically I've defined two functions get.
One with type signature:
get :: A -> Int
And the second:
get :: B -> Double
However, there's a lot of cruft in the code above. What I'd like to be able to do is this:
get :: A -> Int
get (A x) = x
get :: B -> Double
get (B x) = x
I understand using this syntax exactly won't work, but is there any way I can get what I want to achieve without a dozen lines defining type instances and class instances? Considering first code works fine, I see no reason why the Haskell compiler can't this shorter code into the above anyway.
This should do the job:
class Get a b | a -> b where
get :: a -> b
instance Get A Int where
...
https://www.haskell.org/haskellwiki/Functional_dependencies
Okay, so it only got rid of type families. I don't think you can get rid of type classes, as they are the method of implementing overloading. Besides, without a class, you would not be able to express class constraints in types, e.g. you could not write this:
getPaired :: (Get a b, Get c d) => (a, c) -> (b, d)
I don't know if this is applicable to your use case - your example is rather contrived. But you can use a GADT instead of type classes here:
data T a where
A :: Int -> T Int
B :: Double -> T Double
get :: T a -> a
get (A x) = x
get (B x) = x
In general, there is no way to get the compiler to guess what code you want to write and write it for you. Such a compiler would obsolete a majority of programmers, I suspect, so we should all be glad it doesn't exist. I do agree that you are writing quite a lot to do very little, but perhaps that is a sign there is something wrong with your code, rather than a deficit in the compiler.
Here is another alternative:
{-# LANGUAGE TypeFamilies #-}
data A = A Int
data B = B Double
class Get a where
type F a
get :: a -> F a
instance Get A where
type F A = Int
get (A x) = x
instance Get B where
type F B = Double
get (B x) = x
main = print (get (A 3), get (B 2.0))
It looks nicer to me, than functional dependencies.
All the stuff is described at https://www.haskell.org/haskellwiki/GHC/Type_families

Omitting constructor arguments in Haskell case statements

Omitting function arguments is a nice tool for concise Haskell code.
h :: String -> Int
h = (4 +) . length
What about omitting data constructor arguments in case statements. The following code might be considered a little grungy, where s and i are the final arguments in A and B but are repeated as the final arguments in the body of each case match.
f :: Foo -> Int
f = \case
A s -> 4 + length s
B i -> 2 + id i
Is there a way to omit such arguments in case pattern matching? For constructors with a large number of arguments, this would radically shorten code width. E.g. the following pseudo code.
g :: Foo -> Int
g = \case
{- match `A` constructor -> function application to A's arguments -}
A -> (4 +) . length
{- match `B` constructor -> function application to B's arguments -}
B -> (2 +) . id
The GHC extension RecordWildCards lets you concisely bring all the fields of a constructor into scope (of course, this requires you to give names to those fields).
{-# LANGUAGE LambdaCase, RecordWildCards #-}
data Foo = Foo {field1, field2 :: Int} | Bar {field1 :: Int}
baz = \case
Foo{..} -> 4 + field2
Bar{..} -> 2 + field1
-- plus it also "sucks in" fields from a scope
mkBar400 = let field1 = 400 in Bar{..}
`
You can always refactor case statements on constructors into a single function so that from then on you only pass your concise function definitions as arguments to these specific functions. Allow me to illustrate.
Consider the Maybe a datatype:
data Maybe a = Nothing | Just a
Should you now need to define a function f :: Maybe a -> b (for some fixed b and perhaps also a), instead of writing it like
f Nothing = this
f (Just x) = that x
you could start by first defining a function
maybe f _ Nothing = f
maybe _ g (Just x) = g x
and then f can by defined as maybe this that. Pretty much as what happens with all the familiar recursion patterns.
This way you're effectively refactoring out case statements. The code gets arguably cleaner and it does not require language extensions.

Challenged by types

The problem:
Currently I have a type WorkConfig, which looks like this
data WorkConfig = PhaseZero_wc BuildConfig
| PhaseOne_wc BuildConfig Filename (Maybe XMLFilepath)
| PhaseTwo_wc String
| SoulSucker_wc String
| ImageInjector_wc String
| ESX_wc String
| XVA_wc String
| VNX_wc String
| HyperV_wc String
| Finish_wc String
deriving Show
(I'm using String from PhaseTwo_wc on as a placeholder for what will actually be used)
I have a function updateConfig that takes a WorkConfig as one of it's parameters.
The problem is that I want to be able to enforce which constructor is used.
For example in the function phaseOne I want to be able to guarantee that when updateConfig is invoked, only the PhaseTwo_wc constructor can be used.
In order to use a type class for this enforcement, I would have to make separate data constructors, for example:
data PhaseOne_wc = PhaseOne_wc BuildConfig Filename (Maybe XMLFilepath)
If I go this route, I have another problem to solve. I have other data types that have WorkConfig as a value, what would I do to address this? For example,
type ConfigTracker = TMVar (Map CurrentPhase WorkConfig)
How can I use the type system for the enforcement I would like, while keeping in mind what I mentioned above?
ConfigTracker would have to be able to know which data type I wanted.
* Clarification:
I'm looking to restrict which WorkConfig that updateConfig may take as a parameter.
Your question was a little vague, so I will answer in the general.
If you have a type of the form:
data MyType a b c d e f g = C1 a b | C2 c | C3 e f g
... and you want some function f that works on all three constructors:
f :: MyType a b c d e f g -> ...
... but you want some function g that works on just the last constructor, then you have two choices.
The first option is to create a second type embedded within C3:
data SecondType e f g = C4 e f g
... and then embed that within the original C3 constructor:
data MyType a b c d e f g = C1 a b | C2 c | C3 (SecondType e f g)
... and make g a function of SecondType:
g :: SecondType e f g -> ...
This only slightly complicates the code for f as you will have to first unpack C3 to access the C4 constructor.
The second solution is that you just make g a function of the values stored in the C3 constructor:
g :: e -> f -> g -> ...
This requires no modification to f or the MyType type.
To be more concrete and drive the discussion, how close does this GADT & Existential code get to what you want?
{-# LANGUAGE GADTs, KindSignatures, DeriveDataTypeable, ExistentialQuantification, ScopedTypeVariables, StandaloneDeriving #-}
module Main where
import qualified Data.Map as Map
import Data.Typeable
import Data.Maybe
data Phase0 deriving(Typeable)
data Phase1 deriving(Typeable)
data Phase2 deriving(Typeable)
data WC :: * -> * where
Phase0_ :: Int -> WC Phase0
Phase1_ :: Bool -> WC Phase1
deriving (Typeable)
deriving instance Show (WC a)
data Some = forall a. Typeable a => Some (WC a)
deriving instance Show Some
things :: [Some]
things = [ Some (Phase0_ 6) , Some (Phase1_ True) ]
do'phase0 :: WC Phase0 -> WC Phase1
do'phase0 (Phase0_ i) = Phase1_ (even i)
-- Simplify by using TypeRep of the Phase* types as key
type M = Map.Map TypeRep Some
updateConfig :: forall a. Typeable a => WC a -> M -> M
updateConfig wc m = Map.insert key (Some wc) m
where key = typeOf (undefined :: a)
getConfig :: forall a. Typeable a => M -> Maybe (WC a)
getConfig m = case Map.lookup key m of
Nothing -> Nothing
Just (Some wc) -> cast wc
where key = typeOf (undefined :: a)
-- Specialization of updateConfig restricted to taking Phase0
updateConfig_0 :: WC Phase0 -> M -> M
updateConfig_0 = updateConfig
-- Example of processing from Phase0 to Phase1
process_0_1 :: WC Phase0 -> WC Phase1
process_0_1 (Phase0_ i) = (Phase1_ (even i))
main = do
print things
let p0 = Phase0_ 6
m1 = updateConfig p0 Map.empty
m2 = updateConfig (process_0_1 p0) m1
print m2
print (getConfig m2 :: Maybe (WC Phase0))
print (getConfig m2 :: Maybe (WC Phase1))
print (getConfig m2 :: Maybe (WC Phase2))
Sorry, this is more of an extended comment than an answer. I'm a little confused. It sounds like you have some functions like
phaseOne = ...
... (updateConfig ...) ...
phaseTwo = ...
... (updateConfig ...) ...
and you're trying to make sure that eg, inside the definition of phaseOne, this never appears:
phaseOne = ...
... (updateConfig $ PhaseTwo_wc ...) ...
But now I ask you: is updateConfig a pure (non-monadic) function? Because if it is, than phaseOne can easily be perfectly correct and still invoke updateConfig with a PhaseTwo_wc; ie it could just throw away the result (and even if it's monadic too):
phaseOne = ...
... (updateConfig $ PhaseTwo_wc ...) `seq` ...
In other words, I'm wondering if the constraint you're trying to enforce is really the actual property you are looking for?
But now, if we're thinking of monads, there is a common pattern that what you describe is sort of like: making "special" monads that limit the kind of actions that can be performed; eg
data PhaseOneMonad a = PhaseOnePure a | PhaseOneUpdate BuildConfig Filename (Maybe XMLFilepath) a
instance Monad PhaseOneMonad where ...
Is this maybe what you're getting at? Note also that PhaseOneUpdate doesn't take a WorkConfig; it just takes the constructor parameters it is interested in. This is another common pattern: you can't constrain which constructor is used, but you can just take the arguments directly.
Hm... still not sure though.

Sort by constructor ignoring (part of) value

Suppose I have
data Foo = A String Int | B Int
I want to take an xs :: [Foo] and sort it such that all the As are at the beginning, sorted by their strings, but with the ints in the order they appeared in the list, and then have all the Bs at the end, in the same order they appeared.
In particular, I want to create a new list containg the first A of each string and the first B.
I did this by defining a function taking Foos to (Int, String)s and using sortBy and groupBy.
Is there a cleaner way to do this? Preferably one that generalizes to at least 10 constructors.
Typeable, maybe? Something else that's nicer?
EDIT: This is used for processing a list of Foos that is used elsewhere. There is already an Ord instance which is the normal ordering.
You can use
sortBy (comparing foo)
where foo is a function that extracts the interesting parts into something comparable (e.g. Ints).
In the example, since you want the As sorted by their Strings, a mapping to Int with the desired properties would be too complicated, so we use a compound target type.
foo (A s _) = (0,s)
foo (B _) = (1,"")
would be a possible helper. This is more or less equivalent to Tikhon Jelvis' suggestion, but it leaves space for the natural Ord instance.
To make it easier to build comparison function for ADTs with large number of constructors, you can map values to their constructor index with SYB:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Generics
data Foo = A String Int | B Int deriving (Show, Eq, Typeable, Data)
cIndex :: Data a => a -> Int
cIndex = constrIndex . toConstr
Example:
*Main Data.Generics> cIndex $ A "foo" 42
1
*Main Data.Generics> cIndex $ B 0
2
Edit:After re-reading your question, I think the best option is to make Foo an instance of Ord. I do not think there is any way to do this automatically that will act the way you want (just using deriving will create different behavior).
Once Foo is an instance of Ord, you can just use sort from Data.List.
In your exact example, you can do something like this:
data Foo = A String Int | B Int deriving (Eq)
instance Ord Foo where
(A _ _) <= (B _) = True
(A s _) <= (A s' _) = s <= s'
(B _) <= (B _) = True
When something is an instance of Ord, it means the data type has some ordering. Once we know how to order something, we can use a bunch of existing functions (like sort) on it and it will behave how you want. Anything in Ord has to be part of Eq, which is what the deriving (Eq) bit does automatically.
You can also derive Ord. However, the behavior will not be exactly what you want--it will order by all of the fields if it has to (e.g. it will put As with the same string in order by their integers).
Further edit: I was thinking about it some more and realized my solution is probably semantically wrong.
An Ord instance is a statement about your whole data type. For example, I'm saying that Bs are always equal with each other when the derived Eq instance says otherwise.
If the data your representing always behaves like this (that is, Bs are all equal and As with the same string are all equal) then an Ord instance makes sense. Otherwise, you should not actually do this.
However, you can do something almost exactly like this: write your own special compare function (Foo -> Foo -> Ordering) that encapsulates exactly what you want to do then use sortBy. This properly codifies that your particular sorting is special rather than the natural ordering of the data type.
You could use some template haskell to fill in the missing transitive cases. The mkTransitiveLt creates the transitive closure of the given cases (if you order them least to greatest). This gives you a working less-than, which can be turned into a function that returns an Ordering.
{-# LANGUAGE TemplateHaskell #-}
import MkTransitiveLt
import Data.List (sortBy)
data Foo = A String Int | B Int | C | D | E deriving(Show)
cmp a b = $(mkTransitiveLt [|
case (a, b) of
(A _ _, B _) -> True
(B _, C) -> True
(C, D) -> True
(D, E) -> True
(A s _, A s' _) -> s < s'
otherwise -> False|])
lt2Ord f a b =
case (f a b, f b a) of
(True, _) -> LT
(_, True) -> GT
otherwise -> EQ
main = print $ sortBy (lt2Ord cmp) [A "Z" 1, A "A" 1, B 1, A "A" 0, C]
Generates:
[A "A" 1,A "A" 0,A "Z" 1,B 1,C]
mkTransitiveLt must be defined in a separate module:
module MkTransitiveLt (mkTransitiveLt)
where
import Language.Haskell.TH
mkTransitiveLt :: ExpQ -> ExpQ
mkTransitiveLt eq = do
CaseE e ms <- eq
return . CaseE e . reverse . foldl go [] $ ms
where
go ms m#(Match (TupP [a, b]) body decls) = (m:ms) ++
[Match (TupP [x, b]) body decls | Match (TupP [x, y]) _ _ <- ms, y == a]
go ms m = m:ms

Resources