For an infix operator you you can for a section, i.e., a use of the operator with one operand left out. For instance (* 2) leaves out the first operand, and Haskell defines this to be the same as (\ x -> x * 2). Regarding :: as an operator we should be able to write (:: type) and it should have the obvious meaning (\ x -> x :: type).
I suggest, and I plan sending the haskell-prime mailing list, Haskell should adopt this small extension.
Why? First, the extension is very light weight and has almost no extra intellectual weight for anyone learning Haskell. I'd argue it makes the language simpler because it allows :: to be treated more like an infix operator. But without use cases this would probably not be enough of an argument. Example 1 We want to make a function, canonDouble, that takes a string representing a Double and changes it to the standard Haskell string representing this Double. E.g. canonDouble "0.1e1" == "1.0". A first attempt might look like this:
canonDouble :: String -> String
canonDouble = show . read -- WRONG!
This is, of course, wrong since the compiler cannot guess that the type between read and show should be a Double. We can convey this type information in different ways, e.g.:
canonDouble :: String -> String
canonDouble = show . asDouble . read where asDouble :: Double -> Double asDouble x = x
This is somewhat clumsy. Using my proposed extension we can instead write:
canonDouble :: String -> String
canonDouble = show . (:: Double) . read
This has the obvious meaning, and succinctly describes what we want. Example 2 In ghc 7.8 there is a new, better implementation of Data.Typeable. It used to be (before ghc 7.8) that to get a TypeRep for some type you would have to have a value of that type. E.g., typeOf True gives the TypeRep for the Bool type. If we don't have a value handy of the type, then we will have to make one, e.g., by using undefined. So we could write typeOf (undefined :: Bool).
This way of using undefined is rather ugly, and relies on non-strictness to work. Ghc 7.8 add a new, cleaner way of doing it.
typeRep :: proxy a -> TypeRep
The typeRep function does not need an actual value, but just a proxy for the value. A common proxy is the Proxy type from Data.Proxy:
data Proxy a = Proxy
Using this type we can now get the TypeRep of a Bool by writing typeRep (Proxy :: Proxy Bool). Note that in the type signature of typeRep the proxy is a type variable. This means we can use other values as proxies, e.g., typeRep ( :: [Bool]).
We can in fact use anything as a proxy that has a structure that unifies with proxy a. For instance, if we want a proxy for the type T we could use T -> T, which is the same as (->) T T. The (->) T part makes of it is the proxy and the last T makes up the a.
The extension I propose provides an easy way to write a function of type T -> T, just write (:: T). So to get a TypeRep for Bool we can simply write typeRep (:: Bool). Doesn't that look (deceptively) simple?
In fact, my driving force for coming up with this language extension was to get an easy and natural way to write type proxies, and I think using (:: T) for a type proxy is a as easy and natural as it gets (even if the reason it works is rather peculiar).
Implementation I've implemented the extension in one Haskell compiler and it was very easy to add and it works as expected. Since it was so easy, I'll implement it for ghc as well, and the ghc maintainers can decide if the want to merge it. I suggest this new feature is available using the language extension name SignatureSections.
Extensions Does it make sense to do a left section of ::? I.e., does (expr ::) make sense? In current Haskell that does not make sense, since it would be an expression that lacks an argument that is a type. Haskell doesn't currently allow explicit type arguments, but if it ever will this could be considered.
With the definition that (:: T) is the same as (\ x -> x :: T) any use of quantified or qualified types as T will give a type error. E.g., (:: [a]), which is (\ x -> x :: [a], is a type error. You could imagine a different desugaring of (:: T), namely (id :: T -> T). Now (:: [a]) desugars to (id :: [a] -> [a]) which is type correct. In general, we have to keep quantifiers and qualifiers at the top, i.e., (:: forall a . a) turns into (id :: forall a . a -> a).
Personally, I'm not convinced this more complex desugaring is worth the extra effort.
On a whim (partly inspired by something I read in /r/haskell a short while ago) I tried to compile the following in GHC...module Main (main) where data Test = Test x where x = Maybe x main :: IO () main = putStrLn "Hello"
Unsurprisingly, I got a syntax error referring to that where clause.
But it seems intuitive to me that while that particular recursive type doesn't make much sense, a where clause for types could be useful. Maybe only for abbreviating long type signatures, but still useful.
And perhaps even that recursive type has some theoretical validity in a depth-of-Just-constructors-expressing-natural-numbers way.
Am I making sense, or is this silly?
Has supporting where in types been proposed before?submitted by ninereeds314
[link] [34 comments]
My last blog post detailed a number of changes I was going to be making for package consolidation. A number of those have gone through already, this blog post is just a quick summary of the changes.shakespeare
shakespeare is now a single package. hamlet, shakespeare-css, shakespeare-js, shakespeare-i18n, shakespeare-text, and servius have all been merged in and marked as deprecated. I've also uploaded new, empty versions of those deprecated packages. This means that, in order to support both the old and new versions of shakespeare, you just need to ensure that you have both the shakespeare and deprecated packages listed in your cabal file. In other words, if previously you depended on hamlet, now you should depend on hamlet and shakespeare. When you're ready to drop backwards compatibility, simply put a lower bound of >= 2.0 on shakespeare and remove the deprecated packages.
(Note: this method for dealing with deprecated packages is identical for all future deprecations, I won't detail the steps in the rest of this blog post.)conduit
conduit-extra now subsumes attoparsec-conduit, blaze-builder-conduit, network-conduit, and zlib-conduit. It also includes three modules that used to be in conduit itself: .Text, .Binary, and .Lazy. To deal with this change, simply adding conduit-extra to your dependencies should be sufficient.
The other changes have to do with resourcet. In particular:
- Data.Conduit no longer reexports identifiers from resourcet and monad-control. These should be imported directly from their sources.
- Instead of defining its own MonadThrow typeclass, resourcet now uses the MonadThrow typeclass from the exceptions package. For backwards compatibility, Control.Monad.Trans.Resource provides monadThrow as an alias for the new throwM function.
- The Resource monad had a confusing name, in that it wasn't directly related to the ResourceT transformer. I've renamed it to Acquire, and put it in its own module (Data.Acquire).
- I'm actually very happy with Acquire, and think it's a great alternative to hard-coding either the bracket pattern or resourcet into libraries. I'm hoping to add better support to WAI for Acquire, and blog a bit more about the usage of Acquire.
- MonadUnsafeIO has been removed entirely. All of its functionality can be replaced with MonadPrim and MonadBase (for example, see the changes to blaze-builder-conduit).
- MonadActive, which is only needed for Data.Conduit.Lazy, has been moved to that module.
http-client-multipart has been merged into http-client. In addition, instead of using the failure package, http-client now uses the exceptions package.
http-client-conduit has been merged into http-conduit. I've also greatly expanded the Network.HTTP.Client.Conduit module to contain what I consider its next-gen API. In particular:
- No usage of ResumableSource.
- Instead of explicit ResourceT usage, it uses the Acquire monad and bracket pattern (acquireResponse, withResponse).
- Instead of explicitly passing around a Manager, it uses MonadReader and the HasHttpManager typeclass.
I'm curious how people like the new API. I have no plans on removing or changing the current Network.HTTP.Conduit module, this is merely an alternative approach.Updated yesod-platform
I've also released a new version of yesod-platform that uses the new versions of the packages above. A number of packages on Hackage still depend on conduit 1.0, but I've sent quite a few pull requests in the past few days to get things up-to-date. Thankfully, maintaining compatibility with both 1.0 and 1.1 is pretty trivial.