Consider the following classes:
class F t where
f1 :: ...
f2 :: ...
class F t => G t where
g1 :: ...
g2 :: ...
Also I can write the following default functions:
f1 in terms of f2.
f2 in terms of f1.
g1 in terms of g2.
g2 in terms of g1.
f1 in terms of g1, if G t.
f2 in terms of g2, if G t.
Hence, I should be able to do the following:
instance F T1 where
f1 x = (some function of f2)
Or:
instance F T1
instance G T1 where
g1 x = (some function of g2)
But it seems the only way I can achieve this is to have two default definitions of f1 and f2, but I don't think GHC allows this. Is there anyway I can write this so that for both types that are only of class F, and types that are also of class G, only have to implement one function?
If I get the requirements right, they can be straightforwardly satisfied with a couple of extensions:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
class F t where
f1 :: t -> t -> t
f1 _ = f2
f2 :: t -> t
f2 x = f1 x x
class F t => G t where
g1 :: t -> t -> t
g1 x _ = g2 x
g2 :: t -> t
g2 x = g1 x x
instance G t => F t where
f1 = flip g1
f2 = g2
instance F Int where
f1 = (-)
main = mapM_ print ([f1 4 2, f2 4] :: [Int])
*Main> :main
2
0
The instance can be changed to G:
instance G Int where
g1 = subtract
main = mapM_ print ([f1 4 2, f2 4, g1 4 2, g2 4] :: [Int])
*Main> :main
2
0
-2
0
However, I'd consider this solution poor. Could this duality be expressed in some other way? If you provide a concrete example of what F and G are, a more suitable design may be found.
A fairly common idiom for defining subclass methods in terms of the superclass (or is it superclass methods in terms of the subclass? I can never keep it straight) is to expose an explicit *Default method, as in
class F t where
{-# MINIMAL f1 | f2 #-}
f1 = ... f2 ...
f2 = ... f1 ...
f1Default :: G t => ...
f1Default = ... g1 ...
f2Default :: G t => ...
f2Default = ... g2 ...
class G t where
{-# MINIMAL g1 | g2 #-}
g1 = ... g2 ...
g2 = ... g1 ...
This gives the instance-writer control over which default is used.
There are many examples of this pattern in base, including fmapDefault, foldMapDefault, bimapDefault, bifoldMapDefault, and many more, and I expect there are a fair number of examples of this outside base as well.
Related
Given the following code:
{-# OPTIONS_GHC -funbox-strict-fields #-}
module Test where
data X = X !Int !Int
test (X a b) (X c d) = X (max a c) (max b d)
GHC generates this core when compiling with optimizations (renamed to make reading easier):
test
test =
\ u v ->
case u of x { X y z ->
case v of c { X d e ->
case tagToEnum# (<=# y d) of _ {
False ->
case tagToEnum# (<=# z e) of _ {
False -> x;
True -> X y e
};
True ->
case tagToEnum# (<=# z e) of _ {
False -> X d z;
True -> c
}
}
}
}
Note how GHC has generated in total 4 different code paths. In general, the number of code paths grows exponentially with the number of conditions.
What GHC optimization leads to that behavior? Is there a flag to control this optimization? In my case, this generates huge code bloat, and makes core dumps very hard to read because of deeply nested case expressions.
After some research, I've found that the optimization responsible for this is the so called "case-of-case" transformation, that GHC does presumably in the simplifier, so it cannot be deactivated (since it is necessary for a lot of what GHC does and the simplifier is an integral part of GHC's optimization pipeline).
The following link explains how case of case leads to the duplication: http://lambda.jstolarek.com/2013/01/taking-magic-out-of-ghc-or-tracing-compilation-by-transformation/
In particular, case-of-case turns this:
case (
case C of
B1 -> F1
B2 -> F2
) of
A1 -> E1
A2 -> E2
into the following:
case C of
B1 -> case F1 of
A1 -> E1
A2 -> E2
B2 -> case F2 of
A1 -> E1
A2 -> E2
where the outer case has been duplicated and pushed into the branches.
This question already has answers here:
Haskell syntax for 'or' in case expressions
(5 answers)
Closed 7 years ago.
I'm trying to match on many different constructors in a case statement. For simplicity, assume in half the cases we do the same thing, and in the other half we do something else. Even if I factor out the logic to another function, I still have to write:
case x of
C1 -> foo x
C2 -> foo x
...
C10 -> bar x
C11 -> bar x
...
Is there some way to make case statements behave more like switch statements in C (i.e. with fallthrough), or so that I can match on one of many patterns at once, like:
case x of
C1, C2, C3 -> foo x
C10, C11, C12 -> bar x
Or perhaps another way to clean this up?
These are called disjunctive patterns, and Haskell does not have them. (OCaml and F# do.) There are a few typical workarounds, however. If your type is an enumeration, you can use equality, with for example elem, using a case expression, guards, or MultiWayIf:
exampleCase cond = case cond of
c
| c `elem` [C1, C2, C3] -> foo
| c `elem` [C10, C11, C12] -> bar
| otherwise -> baz
exampleGuards c
| c `elem` [C1, C2, C3] -> foo
| c `elem` [C10, C11, C12] -> bar
| otherwise -> baz
exampleIf c
= additionalProcessing $ if
| c `elem` [C1, C2, C3] -> foo
| c `elem` [C10, C11, C12] -> bar
| otherwise -> baz
And of course, if foo or bar are long expressions, thanks to laziness you can simply factor them into local definitions, so you only have to repeat the name and any pattern variables you need as arguments:
exampleWhere cond = case cond of
C1 x -> foo x
C2 y -> foo y
…
C10 -> bar
C11 -> bar
…
where
foo x = something long (involving x, presumably)
bar = if you please then something else quite long
If you frequently group constructors together in this way, you can use the PatternSynonyms language option, which is especially useful in conjunction with ViewPatterns, to make your own patterns for matching such groups:
{-# Language
LambdaCase,
PatternSynonyms,
ViewPatterns #-}
-- Write one function to match each property.
fooish :: T -> Maybe X
fooish = \ case
C1 x -> Just x
C2 x -> Just x
…
C10 -> Nothing
C11 -> Nothing
…
-- May use a wildcard ‘_’ here; I prefer not to,
-- to require updating cases when a type changes.
barrish :: T -> Bool
barrish = \ case
C1{} -> False
C2{} -> False
…
C10 -> True
C11 -> True
…
-- Create synonyms for matching those properties.
-- (These happen to be unidirectional only.)
pattern Fooish :: T -> Foo
pattern Fooish x <- (fooish -> Just x)
pattern Barrish :: T -> Bar
pattern Barrish <- (barrish -> True)
-- If they cover all cases, tell the compiler so.
-- This helps produce useful warnings with ‘-Wall’.
{-# Complete Fooish, Barrish #-}
-- Use them just like normal patterns.
exampleSynonyms x = case x of
Fooish x -> …
…
Barrish -> …
…
In an effort to understand monads better, I'm attempting to write my own. I'm starting with some non-monadic code, and could use some help translating it into a monad.
Basic idea for this contrived example: for each integer result of a computation, I'd like to track if that integer is even or odd. For example, in 4 + 5 = 9, we might return (9, Odd).
I'd like to be able to chain/compose the calculations with >>=. For example:
return 1 >>= (+2) >>= (+5) >>= (+7) =result=> (15, Odd)
Right now, I have the following non-monadic code:
data Quality = Odd | Even deriving Show
qual :: Integer -> Quality
qual x = case odd x of
True -> Odd
_ -> Even
type Qualifier = (Integer, Quality)
mkQ :: Integer -> Qualifier
mkQ x = (x, qual x)
plusQ :: Qualifier -> Qualifier -> Qualifier
plusQ (x, _) (y, _) = (x+y, qual (x+y))
chain = plusQ (mkQ 7) . plusQ (mkQ 5) . plusQ (mkQ 2)
What are some ways I can translate the above code into a monad? What are some of the patterns I should look for, and what are common translation patterns for them?
Many thanks in advance!
I think what you actually want is a Num instance for Qualified:
data Qualified = Qualified { isEven :: Bool, value :: Integer }
instance Num Qualified where
(Qualified e1 n1) + (Qualified e2 n2) = Qualified e (n1 + n2)
where
e = (e1 && e2) || (not e1 && not e2)
(Qualified e1 n1) * (Qualified e2 n2) = Qualified (e1 || e2) (n1 * n2)
abs (Qualified e n) = Qualified e (abs n)
signum (Qualified e n) = Qualified e (signum n)
fromInteger n = Qualified (even n) n
This lets you manipulate Qualified numbers directly using math operators:
>>> let a = fromInteger 3 :: Qualified
>>> let b = fromInteger 4 :: Qualified
>>> a
Qualified {isEven = False, value = 3}
>>> b
Qualified {isEven = True, value = 4}
>>> a + b
Qualified {isEven = False, value = 7}
>>> a * b
Qualified {isEven = True, value = 12}
Lots of learning from this one. Many thanks to the commentors and answers for your time and guidance!
To summarize:
Solution: As #n.m. and others commented, there isn't a good monad translation for this example because my original model isn't type-generic. Monads are best for type-generic computation patterns. Good examples given include the Maybe monad for computations which may fail, and State monad for storing and carrying along accessory state information through a computation chain.
As an alternate solution, #GabrielGonzalez offered a great solution using type instancing. This keeps the inherent type-specificity of my original model, but broadens its interface to support more of the Num type class interface and clean up the functional interactions.
Next steps: As #weirdcanada and others recommended, I think I'll go play with the State monad and see how I can apply it to this particular example. Then I may try my hand at a custom definition of Maybe as #n.m. recommended.
Again, many thanks to those who commented and responded!
An elementary Haskell question:
I would like to "tag functions" in Haskell: I have a list
scheme = [ f1, f2, f3, ... ]
which is built from some simple functions, some of them belonging to a certain group:
f1 :: a -> a
f1 a = ...
f2 :: a -> a -- "belongs to group"
f2 a = ...
f3 :: a -> a
f3 a = ...
f4 :: a -> a -- "belongs to group"
f4 a = ...
...
I want to create a smaller list, containing only the functions belonging to that subgroup:
filter belongsToGroup scheme
In Java, the functions would be subclasses of a Function class, some of them implementing an empty tagging interface FunctionGroup. The filter function could then be realized with the operator instanceof
I tried to understand how I could mimic this behaviour in Haskell (studying "type classes"), but had no success.
Any help?
Haskell actively discourages you from using type system escape hatches. (An instanceof-like construct would break some nice type system properties such as parametricity.) You most likely want to use this type:
type TaggedFunction a b = (a -> b, Bool)
Where first component is just the regular function you want to use, and the second component is True when the function belongs to the group, or False otherwise.
Then you filter TaggedFunctions like this: filter snd tfs
One approach to this problem would be to create a data type representing these functions.
data TaggedFunction a = UsefulFunction (a -> a)
| UselessFunction (a -> a)
f1 :: TaggedFunction a
f1 = UsefulFunction $ \x -> x
f2 :: TaggedFunction a
f2 = UselessFunction $ \x -> x
isUseful :: TaggedFunction a -> Bool
isUseful (UsefulFunction _) = True
isUseful _ = False
main :: IO ()
main = do
let fs = [f1, f2, f1, f2]
useful = filter isUseful fs
print $ (_f $ head useful) 4
This method is easily expandable to include more than two groups, and could even be automatically generated with e.g. Template Haskell.
Edit
After a bit of playing around, I like this refactor of TaggedFunction better.
data TaggedFunction a = Group1 { _f :: a }
| Group2 { _f :: a }
| Group3 { _f :: a }
f1 :: TaggedFunction (a -> a)
f1 = Group1 $ \x -> x
f2 :: TaggedFunction (a -> a)
f2 = Group2 $ \x -> x
isGroup :: Int -> TaggedFunction a -> Bool
isGroup 1 (Group1 _) = True
isGroup 2 (Group2 _) = True
isGroup 3 (Group3 _) = True
isGroup _ _ = False
main :: IO ()
main = do
let fs = [f1, f2, f1, f2]
useful = filter (isGroup 1) fs
print $ length useful
print $ (_f $ head useful) 4
Output:
λ> main
2
4
Note that isGroup is now not total (which I don't like), but it was more convenient than individual isGroupN functions for the purposes of this example.
Often I have a function of such pattern:
f :: a -> b
f x = case x of
... -> g ...
... -> g ...
...
... -> g ...
where g = ...
There is an syntactic sugar for almost this case:
f :: a -> b
f ... = g ...
f ... = g ...
...
f ... = g ...
Unfortunately I can't attach my where to it: I'll obviously get bunch of not in scopes.
I can make g a separate function, but it's not nice: my module's namespace will be polluted with utility functions.
Is there any workaround?
I think that your first example isn't bad at all. The only syntactic weight is case x of, plus -> instead of =; the latter is offset by the fact that you can omit the function name for each clause. Indeed, even dflemstr's proposed go helper function is syntactically heavier.
Admittedly, it's slightly inconsistent compared to the normal function clause syntax, but this is probably a good thing: it more precisely visually delimits the scope in which x is available.
No, there is no workaround. When you have multiple clauses for a function like that, they cannot share a where-clause. Your only option is to use a case statement, or do something like this:
f x =
go x
where
go ... = g ...
go ... = g ...
g = ...
...if you really want to use a function form for some reason.
f = g . h -- h is most of your original f
where h ... = ...
h ... = ...
g =
From Haskell 2010 on, or with GHC you can also do:
f x
| m1 <- x = g
| m2 <- x = g
...
where g =
but note that you cannot use the variables bound in the patterns in g. It's equivalent to:
f x = let g = ... in case () of
() -> case x of
m1 -> g
_ -> case x of
m2 -> g
....
Your original solution seems to be the best and only workaround. Syntactically it's not any heavier than direct pattern matching on function parameters if not even lighter.
But just in case if what you need is just to check preconditions and not pattern match don't forget about guards, which allow you to access the where scope freely. But really I see nothing bad in your case of solution.
f :: a -> b
f a
| a == 2 = ...
| isThree a = ...
| a >= 4 = ...
| otherwise = ...
where isThree x = x == 3
With LambdaCase, you can also do this:
{-# language LambdaCase #-}
f :: a -> b
f = \case
... -> g ...
... -> g ...
...
... -> g ...
where g = ...
Is it safe to assume that you consistently use g on most, if not all, of the different branches of the case statement?
Operating with the assumption that f :: a -> b for some a and b (possibly polymorphic), g is necessarily some function of the form c -> d, which means that there must be a way to consistently extract a c out of an a. Call that getC :: a -> c. In that case, the solution would be to simply use h . g . getC for all cases, where h :: d -> b.
But suppose you can't always get the c out of an a. Perhaps a is of the form f c, where f is a Functor? Then you could fmap g :: f c -> f d, and then somehow transform f d into a b.
Just sort of rambling here, but fmap was the first thing that came to mind when I saw that you appeared to be applying g on every branch.