这有点难以解释,但我已经遇到过几次这种情况。
代码如下:
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')
以上引发错误:
• Couldn't match type ‘UTCTime’ with ‘[Char]’
Expected type: String -> IO FilePath
Actual type: FilePath -> IO UTCTime
• In 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)
哪个有道理,但是有办法以某种方式实现上述目标吗?否则我必须做下面的事情,感觉不太可维护:
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')
答案 0 :(得分:6)
您正在遇到Dreaded Monomorphism Restriction。由于优化和代码生成的问题,当GHC看到一个没有显式参数的值时,它会推断出它的单态类型,而不是你期望的更一般的多态类型。
您可以使用NoMonomorphismRestriction
pragma禁用限制,也可以为f
提供明确的参数:
sortF <- let f xs = sortByM xs input in ...
答案 1 :(得分:1)
对你想要的东西做一些假设......在代码结构上往往有很多选择。你可以有一个总和类型(这里不是一个很好的解决方案):
...
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