在Haskell中输入类 - 当选择的类型无关紧要时,如何让GHC选择类型?

时间:2011-04-14 12:10:15

标签: haskell typeclass

这是关于在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 字符串”

  • 我的分析是否正确?或者还有其他事情发生在这里吗?

  • 有没有办法通知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.

1 个答案:

答案 0 :(得分:4)

不,没有办法让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

以上是相同的。 “g f”和“y $ x”是相同的。那么为什么两个不同的实例呢?