How can I break the Haskell statement when the parameter type is not static?

This is a little difficult to explain, but I have come across this situation several times.

The code is as follows:

work :: String -> IO ()
work a = do
  input <- lines <$> getContents
  sortF <- let f = flip sortByM input
    in case a of
        "name" -> f (return . id         :: FilePath -> IO FilePath)
        "time" -> f (getModificationTime :: FilePath -> IO UTCTime)
        _ ->      f (getModificationTime :: FilePath -> IO UTCTime)
  print sortF

sortByM :: (Monad m, Ord a) => (b-> m a) -> [b] -> m [b]
sortByM f x = do
  x' <- mapM f x
  return $ fst <$> (sortBy (comparing snd) $ zip x x')

The above error:

• Couldn't match type ‘UTCTime’ with ‘[Char]’
  Expected type: String -> IO FilePath
    Actual type: FilePath -> IO UTCTimeIn the first argument of ‘f’, namely
    ‘(getModificationTime :: FilePath -> IO UTCTime)’
  In the expression:
    f (getModificationTime :: FilePath -> IO UTCTime)
  In a case alternative:
      "time" -> f (getModificationTime :: FilePath -> IO UTCTime)

What makes sense, but is there a way to somehow achieve the above? Otherwise, I have to do below, which seems less maintainable:

work :: String -> IO ()
work a = do
  input <- lines <$> getContents
  sortF <- case a of
        "name" -> flip sortByM input (return . id         :: FilePath -> IO FilePath)
        "time" -> flip sortByM input (getModificationTime :: FilePath -> IO UTCTime)
        _ ->      flip sortByM input (getModificationTime :: FilePath -> IO UTCTime)
  print sortF

sortByM :: (Monad m, Ord a) => (b-> m a) -> [b] -> m [b]
sortByM f x = do
  x' <- mapM f x
  return $ fst <$> (sortBy (comparing snd) $ zip x x')
+4
source share
2 answers

You are working in a restricted monomorphism constraint . Due to problems with optimization and code generation, when the GHC sees a value that has no explicit arguments, it will output a monomorphic type for it, rather than the more general polymorphic type that you expect.

NoMonomorphismRestriction , f :

sortF <- let f xs = sortByM xs input in ...
+6

, ... , , . ( ):

  ...
  sortF <- let f = flip sortByM input
    in case a of
        "name" -> Left <$> f (return . id         :: FilePath -> IO FilePath)
        "time" -> Right <$> f (getModificationTime :: FilePath -> IO UTCTime)
        _ ->      Right <$> f (getModificationTime :: FilePath -> IO UTCTime)
  either print print sortF

, "" sortF, , Show, Show String:

  ...
  sortF <- let f = flip sortByM input
    in show <$> case a of
        "name" -> f (return . id         :: FilePath -> IO FilePath)
        "time" -> f (getModificationTime :: FilePath -> IO UTCTime)
        _ ->      f (getModificationTime :: FilePath -> IO UTCTime)
  putStrLn sortF

- String:

  ...
  let op | a == "name" = return . show
         | otherwise   = fmap show . getModificationTime
      f x = sortByM x input
  putStrLn =<< f =<< op
+1

Source: https://habr.com/ru/post/1677650/


All Articles