2014-12-18 2 views
6

Предположим, что у меня есть следующие функции:Haskell: Есть ли способ вывести возвращаемый тип функции изнутри функции?

import Data.Typeable 
import Text.Read (reads) 

parse :: (Read b, Typeable b) => String -> IO b 
parse msg = case reads msg of 
     [(value,"")] -> return value 
     _ -> throwIO $ ErrorCall ("could not parse " ++ msg) 

Он разбирает строку в то, что я хочу его. Если строка неверна, она генерирует исключение, отображающее сообщение, которое не удалось выполнить синтаксический анализ.

Я использую эту функцию в сделай блока IO-монады как

(a,b) <- parse msg :: IO (Int,Int) 

и в другом месте, как

s <- parse msg :: IO String 

Теперь, если я хочу, чтобы сделать исключение более подробной отчетности который не читал

import Data.Typeable 
import Text.Read (reads) 

parse :: (Read b, Typeable b) => String -> IO b 
parse msg = case reads msg of 
     [(value,"")] -> return value 
     _ -> throwIO $ ErrorCall ("could not parse " ++ msg ++ " as " ++ 
         show (typeOf something_that_has_type_b)) 

Как получить что-то, что имеет тип b?

Возможный обходной путь будет делать это

import Data.Typeable 
import Text.Read (reads) 

parse :: (Read b, Typeable b) => b -> String -> IO b 
parse dummy msg = case reads msg of 
     [(value,"")] -> return value 
     _ -> throwIO $ ErrorCall ("could not parse " ++ msg ++ " as " ++ 
         show (typeOf dummy)) 

и ссылающегося на него как

s <- parse "" msg :: IO String 

Но это выглядит довольно глупо.

Есть ли способ вывести возвращаемый тип функции изнутри функции?

+0

Дополнительно: Что делать, если вы хотите * вернуть * значения определенного типа по запросу и ошибку, если запрашивается необработанный тип возврата? – Evi1M4chine

ответ

12

Вам не нужна фиктивная переменная, вы можете использовать расширение ScopedTypeVariables.

{-# LANGUAGE ScopedTypeVariables #-} 

parse :: forall b. (Read b, Typeable b) => String -> IO b 
parse msg = case reads msg of 
    [(value,"")] -> return value 
    _ -> error $ "could not parse " ++ msg ++ " as " ++ 
        show (typeOf (undefined :: b)) 
+6

Кажется, что в эти дни все классные дети используют 'Proxy' вместо' undefined' для такого рода вещей. – dfeuer

+0

@dfeuer Да, это правильно. Стыдно использовать 'undefined', когда' Proxy' находится в 'base'. –

+3

Да, современный способ - show (typeRep (Proxy :: Proxy b)) '. – augustss

Смежные вопросы