[英]Type Classes in Haskell - how can I make GHC make a choice of types, when the type chosen doesn't matter?
这是关于在Haskell中使用类型类的问题。
我在尝试编译代码时遇到错误(下面)(下面和https://github.com/chrisdew/haskell-sandbox/blob/master/not_working_but_clean.hs )。
作为刚刚学习Haskell的人,我尝试过遵循GHC的建议,但我认为原因是不同的。
我认为问题是'IO String'或普通'String'类型都可以是'lhello - >> lbracket'的类型,但GHC不知道哪个。
问题是无关紧要,两种类型都可以正常工作。
我已经在https://github.com/chrisdew/haskell-sandbox/blob/master/working_but_ugly.hs上发布了该代码的工作版本。 这将一个 - >>运算符替换为一个新的(非类型类)运算符' - >>>',它强制'lhello - >> lbracket'为'IO String'类型。
我的分析是否正确? 或者还有其他事情发生在这里?
是否有任何方式告知GHC'lhello - >> lbracket'的类型无关紧要,应该选择两种可能性中的任何一种。 或者也许是一个LANGUAGE选项,它允许我指定'最新声明的匹配的类实例获胜',如果有任何未定的。
谢谢,
克里斯。
错误:
chris@chris-linux-desktop:~/nonworkspace/haskell-sandbox$ ghc
not_working_but_clean.hs
not_working_but_clean.hs:40:16:
No instance for (Stream (IO String) (IO String) (IO String) d)
arising from a use of '->>' at not_working_but_clean.hs:40:16-34
Possible fix:
add an instance declaration for
(Stream (IO String) (IO String) (IO String) d)
In the first argument of '(->>)', namely 'lhello ->> lbracket'
In the second argument of '($)', namely
'lhello ->> lbracket ->> putStrLn'
In a stmt of a 'do' expression:
forkIO $ lhello ->> lbracket ->> putStrLn
not_working_but_clean.hs:40:16:
No instance for (Stream d String (IO ()) (IO ()))
arising from a use of `->>' at not_working_but_clean.hs:40:16-47
Possible fix:
add an instance declaration for (Stream d String (IO ()) (IO ()))
In the second argument of `($)', namely
`lhello ->> lbracket ->> putStrLn'
In a stmt of a 'do' expression:
forkIO $ lhello ->> lbracket ->> putStrLn
In the expression:
do { forkIO $ (bracket $ hello) ->> putStrLn;
forkIO $ lhello ->> lbracket ->> putStrLn;
forkIO $ bracket hello ->> putStrLn;
forkIO $ lbracket lhello ->> putStrLn;
.... }
not_working_but_clean.hs:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances,
TypeSynonymInstances, OverlappingInstances #-}
{-# OPTIONS_GHC #-}
module Main (
main
)
where
import Control.Concurrent (forkIO, MVar, newEmptyMVar, putMVar,
takeMVar, ThreadId, threadDelay)
import Control.Monad (forever, liftM)
class Stream a b c d where
(->>) :: a -> (b -> c) -> d
instance Stream (IO d) d (IO c) (IO c) where
f ->> g = f >>= g
instance Stream d d (IO c) (IO c) where
f ->> g = g f
instance Stream d d c c where
x ->> y = y $ x
-- This simply wraps a string in brackets.
bracket :: String -> String
bracket x = "(" ++ x ++ ")"
lbracket :: IO String -> IO String
lbracket x = liftM bracket x
hello :: String
hello = "Hello World!"
lhello :: IO String
lhello = do return hello
main :: IO ()
main = do
forkIO $ (bracket $ hello) ->> putStrLn
forkIO $ lhello ->> lbracket ->> putStrLn
forkIO $ bracket hello ->> putStrLn
forkIO $ lbracket lhello ->> putStrLn
threadDelay 10000000 -- Sleep for at least 10 seconds before exiting.
working_but_ugly.hs:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances,
TypeSynonymInstances, OverlappingInstances #-}
{-# OPTIONS_GHC #-}
module Main (
main
)
where
import Control.Concurrent (forkIO, MVar, newEmptyMVar, putMVar,
takeMVar, ThreadId, threadDelay)
import Control.Monad (forever, liftM)
class Stream a b c d where
(->>) :: a -> (b -> c) -> d
instance Stream (IO d) d (IO c) (IO c) where
f ->> g = f >>= g
instance Stream d d (IO c) (IO c) where
f ->> g = g f
instance Stream d d c c where
x ->> y = y $ x
x ->>> y = y $ x
-- This simply wraps a string in brackets.
bracket :: String -> String
bracket x = "(" ++ x ++ ")"
lbracket :: IO String -> IO String
lbracket x = liftM bracket x
hello :: String
hello = "Hello World!"
lhello :: IO String
lhello = do return hello
main :: IO ()
main = do
forkIO $ (bracket $ hello) ->> putStrLn
forkIO $ lhello ->>> lbracket ->> putStrLn
forkIO $ bracket hello ->> putStrLn
forkIO $ lbracket lhello ->> putStrLn
threadDelay 10000000 -- Sleep for at least 10 seconds before exiting.
不,没有办法让GHC翻转硬币并选择一个。
你的所有实例的类型'c'都与类型'd'相同,所以你可以省略类型'd'并在定义Stream时重用类型'c'。
instance Stream d d (IO c) (IO c) where
f ->> g = g f
instance Stream d d c c where
x ->> y = y $ x
以上都是一样的。 “gf”和“y $ x”是相同的。 那为什么两个不同的实例?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.