haskell hide import of star-operator - haskell

I have:
import qualified GHC.Types as T hiding (Module, (*))
import GHC.TypeNats hiding ((*))
but when I try to define a (*)-operator, it fails:
{-# INLINE (*) #-}
infixl 7 *
(*) :: r -> r -> r
(*) = undefined
with
error:
Ambiguous occurrence ‘*’
It could refer to either ‘T.*’,
imported qualified from ‘GHC.Types’ at ...
or ‘*’,
imported from ‘GHC.TypeNats’ at ...
|
1277 | infixl 7 *
EDIT: the description is currently not reproducible. I will update the question as soon as I can.

Neither GHC.Types nor GHC.TypeNats have a (*) export. They both have a type (*) export. Usually, you can distinguish between term-level (*) and type-level (*) by context, but this is not true in export/import lists. Instead, term-level is taken as default, and you must explicitly say you want to hide the types.
import qualified GHC.Types as T hiding (Module, type (*))
import GHC.TypeNats hiding (type (*))
The reason Module remains unadorned is because the capitalization means it must be either a type, a constructor, or a pattern synonym. Constructors must occur inside grouping () next to their data types, and pattern synonyms must be set apart with pattern, so the Module above is taken to refer to the data type (hiding the data type also hides all of its constructors).
The reason you did not get an error when you tried to hide something that didn't exist is because hiding was designed so that, if the imported module ever stopped exporting something you hid, your module would not fail to compile. After all, the only reason you referenced that thing was to say that you weren't going to reference that thing.

Related

Dealing with ambiguous occurrence in Haskell

I'm importing both Data.Text and Data.List and their respective find functions collapse.
import Data.Text
import Data.List
my_list = [4, 2, 4, 5, 6, 2, 6]
find (\a -> a == 5) my_list
The above code leads to the following error
Ambiguous occurrence ‘find’
It could refer to
either ‘Data.Text.find’, imported from ‘Data.Text’
or ‘Data.List.find’,
imported from ‘Data.List’
(and originally defined in ‘Data.Foldable’)
Is the only solution to use Data.List.find (\a -> a == 5) my_list here, or qualified imports?
What strikes me is that
Data.List.find (\a -> a == 5) my_list
--> Just 5
Data.Text.find (\a -> a == 5) my_list
--> error: Couldn't match expected type ‘Text’ with actual type ‘[Integer]’
From the find function signatures, the compiler is apparently able to understand that Data.Text.find doesn't work with [Integer]. Can't he use this information to decide on which instance of find to use and, in this case, automatically use find from Data.List ?
Is the only solution to use Data.List.find (\a -> a == 5) my_list here, or qualified imports?
As far as I know, yes, there are no other solutions.
The compiler won't try to type-check both options and use the one which makes your code compile. In the most general case, that could lead to an exponential blow-up. Consider, e.g.,
foo a1 a2 .... aN
where each one of a1 .. aN are imported from two distinct modules. Trying which combination type-checks would in principle require to test 2^N combinations.
Further, there's always the chance that the programmer meant to use an identifier from a module, but they made a mistake and the code does not type-check. In this case, the same identifier from the other module might instead type-check, making the code compile but producing the wrong result. (This is a rather contrived example, I know.)
Note that, if in your importing module you only need to use one of the two finds you can hide the other:
import Data.Text hiding (find)
import Data.List
Alternatively, you can provide explicit disjoint import lists:
import Data.Text (pack)
import Data.List (find, zip)
If you need both finds, you can provide a shorter name for the module
import Data.Text as T
import Data.List as L
as then disambiguate using L.find. You won't need the shorter module name except for the doubly imported identifiers. If you use import qualified instead you will need to specify the module name for all imported identifiers.

Import a type family that is an operator in Haskell

GHC.TypeNats exports type family of the following signature:
type family (m :: Nat) + (n :: Nat) :: Nat
How can I import it explicitly? import GHC.TypeNats((+)) does not work, because it says that GHC.TypeNats does not export (+)...
Everything compiles okay when I import whole module implicitly, but this really is not what I want to have in my code.
I am using GHC 8.6.5
From the manual:
There is now some potential ambiguity in import and export lists; for example if you write import M( (+) ) do you mean the function (+) or the type constructor (+)? The default is the former, but with ExplicitNamespaces (which is implied by TypeOperators) GHC allows you to specify the latter by preceding it with the keyword type, thus:
import M( type (+) )

Limit a number to a range (Haskell)

I am exposing a function which takes two parameters, one is a minimum bound and the other is a maximum bound. How can I ensure, using types, that for example the minimum bound is not greater than the maximum bound?
I want to avoid creating a smart constructor and returning a Maybe because it would make the whole usage more cumbersome.
Thank you
This doesn't exactly answer your question, but one approach that sometimes works is to change your interpretation of your type. For example, instead of
data Range = {lo :: Integer, hi :: Integer}
you could use
data Range = {lo :: Integer, size :: Natural}
This way, there's no way to represent an invalid range.
This solution uses dependent types (and might be too heavyweight, check if dfeuer's answer is enough for your needs).
The solution makes use of the GHC.TypeLits module from base, and also of the typelits-witnesses package.
Here is a difference function that takes two integer arguments (known statically) and complains at compile-time when the first number is greater than the second:
{-# language TypeFamilies #-}
{-# language TypeOperators #-}
{-# language DataKinds #-}
{-# language ScopedTypeVariables #-}
import GHC.TypeLits
import GHC.TypeLits.Compare
import Data.Type.Equality
import Data.Proxy
import Control.Applicative
difference :: forall n m. (KnownNat n,KnownNat m,n <= m)
=> Proxy n
-> Proxy m
-> Integer
difference pn pm = natVal pm - natVal pn
We can check it from GHCi:
ghci> import Data.Proxy
ghci> :set -XTypeApplications
ghci> :set -XDataKinds
ghci> difference (Proxy #2) (Proxy #7)
5
ghci> difference (Proxy #7) (Proxy #2)
** TYPE ERROR **
But what if we want to use the function with values determined at run time? Say, values that we read from console, or from a file?
main :: IO ()
main = do
case (,) <$> someNatVal 2 <*> someNatVal 7 of
Just (SomeNat proxyn,SomeNat proxym) ->
case isLE proxyn proxym of
Just Refl -> print $ difference proxyn proxym
Nothing -> error "first number not less or equal"
Nothing ->
error "could not bring KnownNat into scope"
In this case, we use functions like someNatVal and isLE. These functions might fail with Nothing. If they succeed, however, they return a value that "witnesses" some constraint. And by pattern-matching on the witness, we bring that constraint into scope (this works because the witness is a GADT).
In the example, the Just (SomeNat proxyn,SomeNat proxym) pattern match brings KnownNat constraints for the two arguments into scope. And the Just Refl pattern match brings the n <= m constraint into scope. Only then we can call our difference function.
So, in a way, we have shifted all the busywork of ensuring that the arguments satisfy the required preconditions out of the function itself.
What you're asking for is dependent types. There is a nice tutorial on it in
https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell
Although I don't know how friendly it will be. Do note that dependent typing was improved in GHC 8.0 but I have no experience in that area. I would make sure you're comfortable using template Haskell if you don't want it to be cumbersome.
You needn't invoke the Maybe type to take advantage of 'smart constructors'. If you like, you may accept constructors of either form (min,max) or (max,min) and still create a data type which correctly interprets which is which.
For instance, you could make a little module:
module RangeMinMax (
Range,
makeRange
)
where
data Range = Range (Integer,Integer)
deriving Show
makeRange a b = Range (min a b, max a b)
And now when you create a Range using makeRange, the 2-tuple will automatically be arranged so it's in the form (min,max). Note that the constructor for Range is not exported, so the user of the module is unable to create an invalid Range-- you just need to make sure that you create valid ones in the this module.

Couldn't match kind `*' against `#'

What the heck is going on here:
"Couldn't match kind `*' against `#'"
I was trying the following in GHCi using TemplateHaskell (ghci -XTemplateHaskell)
$(reify ''Show >>= dataToExpQ (const Nothing))
I was hoping to get an Exp out of this (which does have an instance of Show). I am doing this to insert information about haskell types in an application such that it is available as actual data, not as a string.
My goal is the following:
info :: Info
info = $(reify ''Show >>= dataToExpQ (const Nothing))
I really don't understand that error message, what is '#' anyway? If there is #, is there also # -> # or * -> #? Is it something that relates to kinds like kinds relate to types (though I would not know what that could be)?
Okay, so I do understand now that GHC has a hierarchy of kinds and that `#' is a special kind of unboxed types. All well and good, but why does this error pop up? Maybe unboxed types do not play well with genercis?
I'm not fully sure that this makes sense to me yet, since I would consider unboxed types being an optimazition performed by the compiler. I also thought that if an instance of Data exists, it needs to be there for all types that could possible be included in the data structure.
Upon further investigation I believe that Names pose the problem, is there a way to circumvent them in dataToExpQ? How to use that argument anyway?
You're right, it is the Names that cause the problem. More specifically, the problem is that the NameFlavour data type has unboxed integers in some of its fields.
There's a Haddock note on the Data NameFlavor instance that raises some red flags. And if you click through to the source, you'll see that the gfoldl definition essentially treats the unboxed integers like integers. (There's really not much else choice…) This ultimately causes the error you're seeing because dataToExpQ — having been tricked by the deceptive Data NameFlavour instance — builds an Exp term that applies NameU to an (Int :: *) when NameU actually expects an (unboxed) (Int# :: #).
So the problem is that the Data instance for NameFlavour disobeys the invariant assumed by dataToExpQ. But not to worry! This scenario falls squarely under the reason that dataToExpQ takes an argument: the argument lets us provide special treatment for troublesome types. Below, I do this in order to correctly reify the NameFlavour constructors that have unboxed integer fields.
There may be solutions out there for this, but I'm not aware of them, so I rolled up the following. It requires a separate module because of the TH staging restriction.
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MagicHash #-}
module Stage0 where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import GHC.Types (Int(I#))
import GHC.Prim (Int#)
unboxed :: Int# -> Q Exp
unboxed i = litE $ intPrimL $ toInteger $ I# i -- TH does support unboxed literals
nameFlavorToQExp :: NameFlavour -> Maybe (Q Exp)
nameFlavorToQExp n = case n of
NameU i -> Just [| NameU $(unboxed i) |]
NameL i -> Just [| NameL $(unboxed i) |]
_ -> Nothing
And then the following compiles for me.
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Generics.SYB
import Stage0
info :: Info
info = $(reify ''Show >>= dataToExpQ (mkQ Nothing nameFlavorToQExp))
CAVEAT PROGRAMMER The unboxed integers we're bending over backwards for here correspond to "uniques" that GHC uses internally. They are not necessarily expected to be serialized. Depending on how you're using the resulting Info value, this may cause explosions.
Also note when reifying Show, you're also reifying every instance of Show that's in scope.
There's a lot of them — this generates a pretty big syntax term.
As the documentation says, these instances do not include the method definitions.
HTH.

Explicitly import instances

How do I explicitly import typeclass instances? Also, how do I do this with a qualified import?
Currently, I'm doing
import Control.Monad.Error ()
to import the monad instance that I can use for (Either String). Previously, I used
import Control.Monad.Error
I'm not satisfied with either one, because the Monad instance is implicitly imported.
The inability to control imports of instances is one of the trade-offs the Haskell typeclass system makes. Here's an example in a hypothetical Haskell dialect where you can:
Foo.hs:
module Foo where
data Foo = FooA | FooB deriving (Eq, Ord)
Bar.hs:
module Bar (myMap) where
import Data.Map (Map)
import qualified Data.Map as Map
import Foo
myMap :: Map Foo Int
myMap = Map.singleton FooA 42
Baz.hs:
module Baz where
import Data.Map (Map)
import qualified Data.Map as Map
import Foo hiding (instance Ord Foo)
import Bar (myMap)
instance Ord Foo where
FooA > FooB = True
FooB > FooA = False
ouch :: Map Foo Int
ouch = Map.insert FooB 42 myMap
Yikes! The set myMap was created with the proper instance Ord Foo, but it's being combined with a map created with a different, contradictory instance.
Being able to do this would violate Haskell's open world assumption. Unfortunately, I don't know of a good, centralised resource for learning about it. This section of RWH might be helpful (I searched for "haskell open world assumption").
You can't. Instances are always implicitly exported and hence you can't explicitly import them. By the way, Either e's Monad instance is nowadays in Control.Monad.Instances.
Although the generally correct answer would be "no, you can't", I suggest this horrendous solution:
copy + paste
Take a look at the library source code for the desired module, and copy/paste the necessary data declarations, imports, and function definitions into your own code. Don't copy the instances you don't want.
Depending on the problem at hand, the ghc type system extensions OverlappingInstances or IncoherentInstances might be an alternate solution, though this probably won't solve any problems with the base libraries.

Resources