
On 11/03/2013, at 12:10 AM, Peter Caspers wrote:
thanks, this was the core of my question. So by example, if I define a Date type as
data Date = Date Int deriving Show
representing a date by its serial number and want two constructors (conditions are only examples here)
-- smart constructor with serialNumber date serialNumber | serialNumber > 0 = Date serialNumber | otherwise = error ("invalid serialNumber " ++ show serialNumber)
-- smart constructor with day month year date2 day month year | month >= 1 && month <=12 = undefined | otherwise = error ("invalid month " ++ show month)
there is no way of naming both functions date (instead of date2 above, which compiles), right ?
Right.
I still think the basic reason is that
date 5
would then either refer to the first constructor (i.e. representing a date with serial number 5) or a partial application of the second constructor (i.e. representing a function taking month and year and returning the date "5th month, year").
I am having real trouble understanding why you think this. Yes, for an *untyped* language, "date 27" would not know whether to return a date or a closure. But Haskell is *not* an untyped language. The one-identifier-one-visible-interface rule is about making a practical type inference algorithm. I'm also having some trouble understanding why negative serial numbers would be illegal. Dates are a Z-torsor; to convert integers to dates you have to choose an arbitrary origin. My Dershowitz-and-Reingold-inspired Smalltalk calendar library lets you use Julian day number (shifted by 0.5), modified Julian day number, rata die, and ahargana. I've been thinking of allowing a fifth origin: COBOL's 0=31-Dec-1600. "serialNumber" is a bad name because the origin is arbitrary and the name does not reveal what the origin is. You can easily write date :: Either Int (Int Int Int) -> Date date (Left days_since_epoch) = Date days_since_epoch date (Right (year,month,day)) | 1 <= month && month <= 12 && 1 <= day && day <= days_in_month year month = … | otherwise = error ("bad date") Or even set up your own interface type: import System.Time -- to get Month; pity Data.Time doesn't offer that. data Date_Presentation = Julian_Day_Number Int | Modified_Julian_Day_Number Int | Rata_Die Int | Ahargana Int | Days_Since_COBOL_Epoch Int | Gregorian Int Month Int | Julian Int Month Int | Revised_Julian Int Month Int -- more accurate than Gregorian date :: Date_Presentation -> Date date (Julian_Day_Number j) = … … date (Revised_Julian y m d) = … You will notice that this list offers 5 date presentations that use a single number and three that use two numbers and a month name. Overloading is no help with that!
If this is the case, what would be the natural Haskell way of organizing the smart constructors ? Just number them as above ? Or naming them dateFromSerialNumber, dateFromDayMonthYear ?
As noted above, there is NO unique "serial number" for a date and NO unique day/month/year representation either. Smalltalk-80 introduced baStudlyCaps namesThatIsNamesWithInternalCapitals because it was implemented on a machine that used the ASCII 63 left arrow and up arrow instead of the ASCII 67 underscore and caret. So it used the codepoint we associate with underscore for the assignment symbol. In C and C++ and SML and Haskell, we are allowed to use underscores. ThereisnoneedtorunyourwordstogetherOrUseInternalCaps. Nobody_will_shoot_you_for_writing_readably. You should probably take advantage of the module name and call your functions Date.from_julian_day_number :: Int -> Date Date.from_gregorian :: Int -> Month -> Int -> Date
Or would you do it differently from the start ?
One question is support for different calendars. I would probably have a My_Date module that just offers julian day number, modified julian day number, ahagarna, rata die, and maybe a couple of other epochs. I would create nested modules My_Date.Gregorian, My_Date.Julian, My_Date.Revised_Julian, My_Date.Mayan, and so on, so that a new calendar could be supported by just plugging in a new module, not by changing anything. For something without so many alternatives, I might make a different choice.