Deciding whether to create a new package or take over an abandoned one

I would suggest downloading the .tar.gz off of Hackage, and adding a stack.yaml and seeing if an older Stackage lts will get it to compile. Then you can kick the tires a little to see if you would want to take it over.

1 Like

Thank you. I have downloaded .tar.gz and this is the error I get with cabal build

1.329s  ~ % cabal build
Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: clippings-0.2.0 (user goal)
[__1] trying: functor-infix-0.0.5 (dependency of clippings)
[__2] next goal: template-haskell (dependency of functor-infix)
[__2] rejecting: template-haskell-2.18.0.0/installed-2.18.0.0 (conflict:
functor-infix => template-haskell>=2.8 && <2.17)
[__2] skipping: template-haskell-2.20.0.0, template-haskell-2.19.0.0,
template-haskell-2.18.0.0, template-haskell-2.17.0.0 (has the same
characteristics that caused the previous version to fail: excluded by
constraint '>=2.8 && <2.17' from 'functor-infix')
[__2] rejecting: template-haskell-2.16.0.0, template-haskell-2.15.0.0,
template-haskell-2.14.0.0, template-haskell-2.13.0.0,
template-haskell-2.12.0.0, template-haskell-2.11.1.0,
template-haskell-2.11.0.0, template-haskell-2.10.0.0,
template-haskell-2.9.0.0, template-haskell-2.8.0.0, template-haskell-2.7.0.0,
template-haskell-2.6.0.0, template-haskell-2.5.0.0, template-haskell-2.4.0.1,
template-haskell-2.4.0.0, template-haskell-2.3.0.1, template-haskell-2.3.0.0,
template-haskell-2.2.0.0 (constraint from non-upgradeable package requires
installed instance)
[__2] fail (backjumping, conflict set: functor-infix, template-haskell)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, template-haskell, functor-infix,
clippings

Any clues or pointers would be appreciated.

I’ll try that.

The important line is:

[__2] rejecting: template-haskell-2.18.0.0/installed-2.18.0.0 (conflict: 
functor-infix => template-haskell>=2.8 && <2.17)

That means that it requires a template-haskell below 2.17 and template-haskell is a non-reinstallable library so you can only use it with one specific version of GHC. You can look on this GHC wiki page to see that 2.17 corresponds to GHC 9.0, so it may work if you use GHC 8.10.7.

Thank you @jaror.

Doesn’t the error message say that template-haskellversion should be >= 2.8 && ; 2.17 ? And I see it’s impossible to satisfy that constraint.

I used Haskell Playground (GHC 8.10.7) with this code, and I get:

module Main where

import Data.Functor.Infix

main = do
  putStrLn "Hello, World!"
Could not find module ‘Data.Functor.Infix’
    Perhaps you meant
      Data.Functor.Alt (from semigroupoids-5.3.7)
      Data.Functor.Apply (from semigroupoids-5.3.7)
      Data.Functor.Bind (from semigroupoids-5.3.7)
    Use -v (or `:set -v` in ghci) to see a list of the files searched for.

Yes it also has a lowe bound of 2.8, but the upper bound is more important as that’s probably what you want to get closest to. And no, it is not impossible to satisfy. For example 2.17 which comes with GHC 8.10 does satisfy that constraint (note that 2.8 means 2.08 and not 2.80).

The Haskell playground has a limited set of packages available. functor-infix is not in that set.

1 Like

That looks pretty typical of cabal, Hackage say’s the last successful build was with ghc-7.8.3, that would be the Stackage lts-0.7, that’s pretty old…

The Stackage lts-6.35 might be a better bet, since it’s the last of the ghc-7.x series, and only 6 years out of date.

Think of it as going on an adventure in Hackage necromancy!

I’ve looked at the source code. The package functor-infix is only required for the function <$$> in Text.Kindle.Clippings.Reader.

<$$> is simply a convenience function equal to fmap . fmap. Because it’s such a small amount of code, I suggest removing the dependency on functor-infix and copying the definition of <$$> from functor-infix directly into Text/Kindle/Clippings/Reader.hs. That should make it possible to use a recent Stackage version.

1 Like

I’m actually not sure.

There is one counter argument to it: I often choose the packages I frequently depend on by the author/maintainer, less so by features and API. Do I trust them, do I know they’re experts and not just dumping an experiment on hackage?

There’s maintainers I have personally blacklisted, because I don’t trust them to maintain e.g. secure packages.

When a package takeover happens, it’s often hard for users like me to know and reevaluate whether I want to trust the new maintainers.

I guess that could somehow be assisted with tooling, but often times the maintainer field in cabal files isn’t very reliable. Or I simply have never heard of the new maintainer and their hackage footprint is zero.

As such, fluid maintainership can disrupt the trust relationship between users and package.

I’m not advocating to stop package takeovers, but e.g. hackage namespaces could solve this problem.


Edit: that’s also why I’m quite sceptical of things like Haskell GitHub Trust. Do you want lots of people have commit access to crypto packages?

1 Like

that’s also why I’m quite sceptical of things like Haskell GitHub Trust. Do you want lots of people have commit access to crypto packages?

Haskell Github Trust is not for popular important packages lovingly maintained by cryptography experts. It’s for low-interest packages which a small number of people find useful sometimes.

The clippings package

is a perfect candidate for Haskell Github Trust: a parser for Kindle files, with 9 downloads in the last month, last updated in 2015.

4 Likes

Don’t get me wrong, I welcome comaintenance projects. But it does make it harder for people to assess the quality of maintenance.

I raised some of my concerns here: Introduce Haskell Party proposal by bergmark · Pull Request #12 · haskellfoundation/stability · GitHub

I’d personally only use such comaintenance if I could define a custom patch policy (e.g. no feature patches in my absence, or no major refactorings). But at that point, I’m probably better off managing my contributors directly.

I don’t have a definite answer on the topic as a whole, but wanted to share my doubts.

1 Like

Thank you everyone for your valuable inputs !

That’s very funny ! I am enjoying the ride so far.

Thank you so much. That did it. Compilation is successful now.

parseDate :: String -> LocalTime
parseDate raw = fromMaybe defaultLocalTime . join . find isJust . map (fst <$$> flip strptime raw) $
  [ "%A, %d %B %y %X"  -- Thursday, 01 January 70 12:00:00 AM
  , "%A, %B %d, %Y %r" -- Thursday, January 01, 1970 12:00:00 AM
  ]

defaultLocalTime :: LocalTime
Just (defaultLocalTime, _) = strptime "" ""

I noticed that section of code, raises the following warning:

src/Text/Kindle/Clippings/Reader.hs:87:1: warning: [-Wincomplete-uni-patterns]
    Pattern match(es) are non-exhaustive
    In a pattern binding:
        Patterns of type ‘Maybe (LocalTime, String)’ not matched: Nothing
   |
87 | Just (defaultLocalTime, _) = strptime "" ""

Is there a more up-to-date way to handle the parsing of that date ?

I asked haskell-cafe about takeover process, and they said publicly annoncíng my intention on discourse is fine, since I can’t suscribe to haskell-cafe mailing list.

Instead of:

Just (defaultLocalTime, _) = strptime "" ""

You can do:

defaultLocalTime =
  case strptime "" "" of
    Just (x, _) -> x
    Nothing -> error "No default local time"

Or some other error message.

Thank you, @jaror. I just wondered (sorry for not being clear), is there is an alternative way of getting the default local time, without using strptime and just relying on Data.Time.LocalTime (or another submodule of Data.Time)

I think it should always return 1970-01-01 00:00:00 +0000, so you could write that manually as:

defaultLocalTime = LocalTime (YearDay 1970 1) (TimeOfDay 0 0 0)

Thank you, but the error reads:

• Illegal term-level use of the type constructor ‘LocalTime’
    imported from ‘Data.Time.LocalTime’

Looking at the definition:

-- | Bidirectional abstract constructor for ISO 8601 Ordinal Date format.
-- Invalid day numbers will be clipped to the correct range (1 to 365 or 366).
pattern YearDay :: Year -> DayOfYear -> Day
pattern YearDay y d <-
    (toOrdinalDate -> (y, d))
    where
        YearDay y d = fromOrdinalDate y d

Do you understand what’s that pattern keyword there ? I’ve never came across this. Is that a pattern synonym ?

You should still import the LocalTime term constructor.

That’s part of the PatternSynonyms extension.

Here’s a fully working program with explicit imports:

{-# LANGUAGE PatternSynonyms #-}

import Data.Time.Calendar.OrdinalDate (pattern YearDay)
import Data.Time.LocalTime (LocalTime (LocalTime), TimeOfDay (TimeOfDay))

defaultLocalTime = LocalTime (YearDay 1970 1) (TimeOfDay 0 0 0)

Alternatively you can avoid PatternSynonyms by using fromOrdinalDate which does the same thing as YearDay:

import Data.Time.Calendar.OrdinalDate (fromOrdinalDate)
import Data.Time.LocalTime (LocalTime (LocalTime), TimeOfDay (TimeOfDay))

defaultLocalTime = LocalTime (fromOrdinalDate 1970 1) (TimeOfDay 0 0 0)
1 Like

I agree with this way of proceeding. My motivation is a bit different: long term maintenance of existing packages results in a more stable, reliable and economic Haskell ecosystem.

2 Likes