Solutions for "multiple declarations" in Haskell sum data types? - haskell

GHC 9.2.4 gives a multiple declaration error for the following code:
data X = A | B | C
data Y = A | B | C
There are so many new extensions in GHC nowadays. Is there one that allows me to do the above (since it is semantically appropriate for my problem domain) or is the common solution still to prefix, like data X = XA | XB | XC ?

Even without any extensions, you can declare the two types in different modules. You say in a comment "I wish these things can be namespaced"; the module system is namespaces.
module X where
data X = A | B | C
module Y where
data Y = A | B | C
module OnlyUsesX where
import X
foo :: Char -> Maybe X
foo 'a' = Just A
foo 'b' = Just B
foo 'c' = Just C
foo _ = Nothing
module UsesBoth where
import X (X) -- import only the type name unqualified, since
-- it's unambiguous
import qualified X as X -- also import the entire module qualified, for
-- the ambiguous stuff
import Y (Y)
import qualified Y as Y -- the "as Y" is pointless here, but normally the
-- full module name is longer; if you use the type
-- name as the module alias, then it looks like you
-- have a namespace associated with the type, much
-- like OO code
foo :: X -> Y -> String
foo X.A Y.A = "both A"
foo X.B Y.B = "both B"
foo _ _ = "I can't be bothered enumerating the rest of the possibilities"
If you put your types in small modules dedicated to just that one type, then in other modules where you use multiple types you can refer to the types as simply X or Y, and constructors/fields of the type as X.whatever
or Y.whatever.
This lets you use short prefixless names in the constructor/field names themselves (which avoids the prefixes infecting derived read/show/json/etc instances, if you care about that). Where there isn't any usage of conflicting names you have the option of importing unqualified and dropping the prefixes, which you wouldn't have if the prefix was baked into the actual constructor/field names. And it also avoids any ambiguous inference problems that a hypothetical version of GHC would necessarily have if it allowed duplicate constructor/pattern names in the same namespace and tried to use types to resolve which is which; if you ever use conflicting imported names in the same namespace the compiler will tell you and you can just use the module prefix to resolve it for the benefit of both the compiler and any human readers.

You should prefix them, or put them in separate modules. And probably you should also use them this explicitly qualified way.
However if you insist, you can fake constructors that are polymorphic to work for both cases, by using a type class and constructing patterns synonyms over it. In this case, the easiest way is to use the fact that both of these are isomorphic to X:
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
class HasABCConstructors w where
fromX :: X -> w
toX :: w -> X
instance HasABCConstructors X where
fromX = id
toX = id
instance HasABCConstructors Y where
fromX XA = YA
fromX XB = YB
fromX XC = YC
toX YA = XA
toX YB = XB
toX YC = XC
pattern A :: HasABCConstructors w => w
pattern A <- (toX -> XA)
where A = fromX XA
ghci> A :: X
XA
ghci> A :: Y
YA

Related

NamedFieldPuns, Pattern matching using variable name

{-# LANGUAGE NamedFieldPuns #-}
data Factory = Factory { fId :: Int}
data Link = Link Int Int Double
hasLinkTo :: Factory -> Link -> Bool
hasLinkTo Factory{fId} (Link fId _ _) = True
Got error
• Conflicting definitions for ‘fId’ Bound at: <source.hs> In an equation for ‘hasLinkTo’
I know using variables could fix it,
hasLinkTo Factory{fId=a} (Link b _ _) = a == b
I want to ask for
reason of compilation fail, to better understand how pattern matching work.
is there any idiomatic way to write the function?
for example: if I want to extract what link to a node i, I want to write something like this
connected :: Int -> Link -> (Int, Double)
connected i (Link i j d) = (j,d)
connected i (Link j i d) = (j,d)
Is there any way to check for (==) using only pattern matching on non-numeric literals?
connected 0 (Link 0 j d) = (j,d) is working fine. but the above example won't.
Record punning with Factory{fId} is only syntactic sugar which GHC expands to Factory{fId=fId}. This declared a variable named fId with the value of the field named fId from the Factory record.
Furthermore, pattern matching only declares variables. It does not allow you to compare them by repeating the same name. Consider an attempt to compare equality:
eq a a = True
eq _ _ = False
This is a simple example that tried to do the same thing you are. It will not compile, though.
In the same way, the compiler complains because you declare two variables when you do (Link fId _ _). This is not allowed. Instead you need to use another name and explicitly compare the two:
hasLinkTo Factory{fId} (Link fInd' _ _) = fId == fId'
Haskell only allows linear patterns, where each variable can appear at most once. I believe that this was a deliberate design choice. Theoretically speaking
case e1 of C x x y -> e2 ; ...
could be automatically translated to
case e1 of C x1 x2 y | x1==x2 -> e2 ; ...
This would mean that non linear patterns require an additional Eq constraint for the types of non-linear variables. Further, it could be argued that it is possible for a programmer to accidentally reuse a variable by mistake, which would be silently ignored and lead to the unintended semantics if we allowed non-linear patterns.
Probably, the Haskell designers felt that adding | x1==x2 to a pattern was not too cumbersome and makes the intent more explicit.
For numeric literals, however, they kept this translation. A pattern
case e1 of K 0 y z -> e2 ; ...
does translate to
case e1 of K x y z | x==0 -> e2 ; ...
and does require Eq. Since 0 is not a variable, we no longer have the issues of non-linear patterns.
Anyway, the idiomatic way is to add guards like | x1==x2 to non-liner patterns.
You can't use only pattern matching for this at the moment.

Type error when messing up with lenses [duplicate]

This question already has answers here:
Why do 3 and x (which was assigned 3) have different inferred types in Haskell? [duplicate]
(3 answers)
Closed 7 years ago.
I am encountering a type error when trying to compile some lens code.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens.Setter (over)
import Control.Lens.Getter (view)
import Control.Lens.TH
data IL = IL {
_ilL :: [Int]
}
deriving (Show)
makeLenses ''IL
val = IL [1, 2, 3]
(val1, val2) = let l = ilL
in (over l tail val, view l val)
The error is:
Test.hs:17:35:
Couldn't match expected type `Control.Lens.Internal.Getter.Accessor [Int] [Int]'
with actual type `Control.Lens.Internal.Setter.Mutator [Int]'
Expected type: Control.Lens.Getter.Getting [Int] s0 [Int]
Actual type: ([Int]
-> Control.Lens.Internal.Setter.Mutator [Int])
-> IL -> Control.Lens.Internal.Setter.Mutator IL
In the first argument of `view', namely `l'
In the expression: view l val
This error goes away if I use ilL directly. However, I really need to make a lens definition using let. How can I solve this?
Yet another case of the dreaded monomorphism restriction. Add {-# LANGUAGE NoMonormorphismRestriction #-} at the top of your file and it will compile just fine.
The reason is because when you do let l = ilL in ... without an explicit type signature (or the MR disabled) GHC wants to specialize the type of l as much as it can. It first encounters its use in over l tail val and specializes to the type needed there, but this conflicts with the specialized inferred type in view l val. The solution is to disable the MR or add explicit type signatures like
(val1, val2) =
let l :: Lens' IL [Int]
l = ilL
in (over l tail val, view l val)
This is very similar to a more simple case like
x = let y = 1
z = 2 :: Int
w = 3 :: Double
in (z + y, w + y)
What should the type of y be? With the MR the compiler wants to restrict the type of y to be a single type, but we would really like it to have the type Num a => a since this can work with Ints or Doubles. With the MR turned off the compiler won't specialize the type of y and everything works as expected. The alternative is to give y an explicit type signature, but why do all that work when we can make the compiler do it for us?

Pattern matching against record syntax

Consider the following data definition:
data Foo = A{field::Int}
| B{field::Int}
| C
| D
Now let's say we want to write a function that takes a Foo and increases field if it exists, and leave it unchanged otherwise:
incFoo :: Foo -> Foo
incFoo A{field=n} = A{field=n+1}
incFoo B{field=n} = B{field=n+1}
incFoo x = x
This naive approach leads to some code duplication. But the fact that both A and B shares field allows us to rewrite it:
incFoo :: Foo -> Foo
incFoo x | hasField x, n <- field x = x{field=n+1}
incFoo x = x
hasField A{} = True
hasField B{} = True
hasField _ = False
Less elegant, but that's defiantly easier to maintain when the actual manipulation is complex. The key feature here is x{field=n+1} - record syntax allows us to "update" field without specifying x's type. Considering this, I'd expect something similar to the following syntax (which is not supported):
incFoo :: Foo -> Foo
incFoo x{field=n} = x{field=n+1}
incFoo x = x
I've considered using View Patterns, but since field is a partial function (field C raises an error) it'll require wrapping it in more boilerplate code.
So my question is: why there's no support for the above syntax, and is there any elegant way of implementing a similar behavior?
Thanks!
The reason why you can't do this is because in Haskell, records are inherently second class. They always must be wrapped in a constructor. So in order to have this work as intended you either must use an individual case for each constructor, or use a record substitute.
One possible solution is to use lenses. I'll use the implementation of lenses lens since lens-family-th doesn't seem to handle duplicate field names.
import Control.Lens
data Foo = A {_f :: Int}
| B {_f :: Int}
deriving Show
makeLenses ''Foo
foo :: Foo -> Foo
foo = f %~ (+1)
And then we can use it like this
> foo (A 1)
A{_f = 1}

Case between two unrelated types in 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

How to have an operator which adds/subtracts both absolute and relative values, in Haskell

(Apologies for the weird title, but I could not think of a better one.)
For a personal Haskell project I want to have the concepts of 'absolute values' (like a frequency) and relative values (like the ratio between two frequencies). In my context, it makes no sense to add two absolute values: one can add relative values to produce new relative values, and add a relative value to an absolute one to produce a new absolute value (and likewise for subtraction).
I've defined type classes for these: see below. However, note that the operators ##+ and #+ have a similar structure (and likewise for ##- and #-). Therefore I would prefer to merge these operators, so that I have a single addition operator, which adds a relative value (and likewise a single subtraction operator, which results in a relative value). UPDATE: To clarify, my goal is to unify my ##+ and #+ into a single operator. My goal is not to unify this with the existing (Num) + operator.
However, I don't see how to do this with type classes.
Question: Can this be done, and if so, how? Or should I not be trying?
The following is what I currently have:
{-# LANGUAGE MultiParamTypeClasses #-}
class Abs a where
nullPoint :: a
class Rel r where
zero :: r
(##+) :: r -> r -> r
neg :: r -> r
(##-) :: Rel r => r -> r -> r
r ##- s = r ##+ neg s
class (Abs a, Rel r) => AbsRel a r where
(#+) :: a -> r -> a
(#-) :: a -> a -> r
I think you're looking for a concept called a Torsor. A torsor consists of set of values, set of differences, and operator which adds a difference to a value. Additionally, the set of differences must form an additive group, so differences also can be added together.
Interestingly, torsors are everywhere. Common examples include
Points and Vectors
Dates and date-differences
Files and diffs
etc.
One possible Haskell definition is:
class Torsor a where
type TorsorOf a :: *
(.-) :: a -> a -> TorsorOf a
(.+) :: a -> TorsorOf a -> a
Here are few example instances:
instance Torsor UTCTime where
type TorsorOf UTCTime = NominalDiffTime
a .- b = diffUTCTime a b
a .+ b = addUTCTime b a
instance Torsor Double where
type TorsorOf Double = Double
a .- b = a - b
a .+ b = a + b
instance Torsor Int where
type TorsorOf Int = Int
a .- b = a - b
a .+ b = a + b
In the last case, notice that the two sets of the torsors don't need to be a different set, which makes adding your relative values together simple.
For more information, see a much nicer description in Roman Cheplyakas blog
I don't think you should be trying to unify these operators. Subtracting two vectors and subtracting two points are fundamentally different operations. The fact that it's difficult to represent them as the same thing in the type system is not the type system being awkward - it's because these two concepts really are different things!
The mathematical framework behind what you're working with is the affine space.
These are already available in Haskell in the vector-space package (do cabal install vector-space at the command prompt). Rather than using multi parameter type classes, they use type families to associate a vector (relative) type with each point (absolute) type.
Here's a minimal example showing how to define your own absolute and relative data types, and their interaction:
{-# LANGUAGE TypeFamilies #-}
import Data.VectorSpace
import Data.AffineSpace
data Point = Point { px :: Float, py :: Float }
data Vec = Vec { vx :: Float, vy :: Float }
instance AdditiveGroup Vec where
zeroV = Vec 0 0
negateV (Vec x y) = Vec (-x) (-y)
Vec x y ^+^ Vec x' y' = Vec (x+x') (y+y')
instance AffineSpace Point where
type Diff Point = Vec
Point x y .-. Point x' y' = Vec (x-x') (y-y')
Point x y .+^ Vec x' y' = Point (x+x') (y+y')
You have two answers telling you what you should do, here's another answer telling you how to do what you asked for (which might not be a good idea). :)
class Add a b c | a b -> c where
(#+) :: a -> b -> c
instance Add AbsTime RelTime AbsTime where
(#+) = ...
instance Add RelTime RelTime RelTime where
(#+) = ...
The overloading for (#+) makes it very flexible. Too flexible, IMO. The only restraint is that the result type is determined by the argument types (without this FD the operator becomes almost unusable because it constrains nothing).

Resources