GHC 7.6 is now live: poly kinds, dynamic use of cores, numeric type literals...
haskell.org
haskell.org
Highlights:
* RTS now supports changing the number of capabilities at runtime
* Dataflow based code gen is on
* Unboxed tuples (register allocated structs) are now first class
* Multi-way if syntax
* Lambda case syntax
* Type level naturals and strings
Also one thing that always gave me pause about Haskell was the record system, and the inability to have fields with the same name in the same module (especially when the fields are generated from a database). Has there been any progress on that front?
There have been a zillion proposals, but as far as I know, not much actual consensus or implementation work.
Anecdotally, I've never run into a situation where this was anything more than a minor annoyance. I don't doubt that it can be a problem under the right set of circumstances, but I think the issue gets more attention than its magnitude truly merits. People theorize a lot about the difficulties it can hypothetically cause, but in practice, it seldom actually manifests itself.
[1] http://www.haskell.org/ghc/docs/latest/html/users_guide/sepa...
I don't have any evidence for this, but I feel like it's often a bit of a code smell when this problem crops up. It seems like it frequently happens when programmers used to OOP are trying to shoehorn an object oriented design into a language which is just fundamentally not object oriented. I'm not saying that that's the only situation in which this problem arises, nor that the complaint isn't a legitimate one, regardless. There is no question that the situation could be improved. And perhaps I've just gotten lucky so far and haven't come across a scenario in which this really causes difficulties.
That said, there are always ways to work around the issue. I will make no claims of elegance here, but it's really not that much trouble. For one, you can define the different record types in separate modules, and then import them qualified. That's easy enough to do; it's just annoying to have to use multiple files.
Alternatively, you can keep the ugly prefixes on the record field names, but then use a type class to elide them away everywhere you refer to them. This technique only works when the similarly-named fields have the same type in each record, unless you use fundeps or associated types to attach additional type information to your class. For example:
{-# LANGUAGE TypeFamilies #-}
data Foo = Foo {foo_field1 :: Char, foo_field2 :: String}
data Bar = Bar {bar_field1 :: Int, bar_field2 :: String}
class MyRecord a where type Field1Type a
field1 :: a -> Field1Type a
field2 :: a -> String
instance MyRecord Foo where type Field1Type Foo = Char
field1 = foo_field1
field2 = foo_field2
instance MyRecord Bar where type Field1Type Bar = Int
field1 = bar_field1
field2 = bar_field2
You could even use Template Haskell to automatically generate the instances so you don't have to tediously type them out yourself, especially handy for records with a large number of fields.So I'm not claiming that there's no problem to be solved. I would be happy to see a real solution to this that doesn't require any workarounds. I just don't think it's a big enough issue to keep me from using a language which is, in nearly all other respects, awesome. :)
Type-level strings (AKA Symbols) also allow very impressive constructs, such as type-safe extensible records using type-level strings as keys.
zipVec :: Vector a n -> Vector b n -> Vector (a, b) n
where Vector a b is the type of a vector of elements of type a that is of length n. The above function will therefore only zip together two vectors if they have the same length; otherwise it's a compile-time error. Right now, people usually roll their own representations of numbers, but this new extension means not only do we have a standard one, we can now write something like myBuffer :: Buffer Int 256 where 256 is a type-level number.With type-level symbols, we could do something like
data StringWrapper (a :: Symbol) = S String
getUserData :: IO (StringWrapper "unsanitized")
writeToDB :: StringWrapper "sanitized" -> IO ()
sanitize :: StringWrapper "unsanitized" -> StringWrapper "sanitized"
stringLength :: StringWrapper a -> Int
so that writing code like do x <- getUserData
putStrLn ("Length is " ++ show (stringLength x))
writeToDb x -- forgetting to sanitize
produces a compile-time error because the types don't match up.http://shootout.alioth.debian.org/u64q/program.php?test=fann...
http://shootout.alioth.debian.org/u32q/program.php?test=fann...
I'm particularly interested in the new type-level literals (which seem like they will make it much less cumbersome to express certain static constraints) and the convenient new syntax for multi-way if expressions (I've long wanted Lisp's `cond` in Haskell) and case analysis on lambda arguments.
Functional `if` and `cond` are here: http://hackage.haskell.org/packages/archive/cond/0.4.0.1/doc...
And the cond you wanted has already been here for you.
curry (\case (Nothing,_) -> ...)
(It seems like this would defeat the purpose of lambda-case for lambdas with more than 2 arguments, and it is awkward even for those with exactly 2 arguments.)[1] http://www.haskell.org/ghc/docs/7.6.1/html/users_guide/synta... [2] http://hackage.haskell.org/trac/ghc/wiki/LambdasVsPatternMat...
See the discussions at http://hackage.haskell.org/trac/ghc/ticket/4359 and https://unknownparallel.wordpress.com/2012/07/09/the-long-an... for the history of this.
Multi-argument lambda case proves quite difficult to handle sanely, because normal non-lambda case doesn't do multiple arguments, just tuples. Having multiple arguments requires separating the pattern for each argument somehow, a problem that doesn't come up for non-lambda cases.