Классы типов в Haskell - как я могу заставить GHC делать выбор типов, когда выбранный тип не имеет значения? - PullRequest
1 голос
/ 14 апреля 2011

Это вопрос об использовании классов типов в Haskell.

Я получаю сообщение об ошибке (ниже) при попытке скомпилировать код (ниже и при https://github.com/chrisdew/haskell-sandbox/blob/master/not_working_but_clean.hs ).

Как кто-то, только изучающий Хаскелл, я пытался следовать советам GHC, но я думаю, что причина в другом.

Я считаю, что проблема в том, что либо типа 'IO String', либо обычный «String» может относиться к типу «lhello - >> lbracket», но GHC этого не делает знать, что.

Проблема в том, что это не имеет значения, любой тип будет работать нормально.

Я разместил рабочую версию кода на https://github.com/chrisdew/haskell-sandbox/blob/master/working_but_ugly.hs , Это заменяет один из операторов - >> новым (не тип класса) оператор '- >>>', который заставляет 'lhello - >> lbracket' иметь тип 'IO Строка».

  • Является ли мой анализ правильным? Или здесь что-то еще происходит?

  • Есть ли способ сообщить GHC, какой тип 'lhello - >> Брэкет 'не имеет значения, и это должно просто выбрать любой из две возможности. Или, возможно, есть вариант ЯЗЫКА, который позволит мне указать, что «последний объявленный соответствующий экземпляр класса выигрывает» если что-то не решено.

Спасибо

Крис.

Ошибка:

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 Ответ

4 голосов
/ 14 апреля 2011

Нет, нет никакого способа заставить GHC подбросить монету и выбрать одну.

Все ваши экземпляры имеют тип 'c' так же, как и тип 'd', так что вы, вероятно, можете опустить тип 'd'и повторно используйте тип' c 'в определении Stream.

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» одинаковы.Так почему два разных экземпляра ??

...