2014-08-30 4 views
2

Я хочу использовать двусмысленный тип a в функции следующим образом, но он терпит неудачу.Невидимая подпись типа в Haskell

foo :: (Read a, Show a) => IO() 
foo = print =<< (readLn :: IO a) 

Целью является получение разных выходов относительно заданной сигнатуры типа при фактическом вызове.

>>> foo :: Double => IO() 
34 -- user input 
34.0 -- output 

>>> foo :: Int => IO() 
34 -- user input 
34 -- output 

Как я могу управлять этим?

+0

К сожалению, я изменил функцию выборки. – user3749167

ответ

9

Простейшим путь - показать вашу переменную типа. Например, используя довольно новый GHC:

{-# LANGUAGE ScopedTypeVariables #-} 
foo :: forall proxy a. (Read a, Show a) => proxy a -> IO() 
foo _ = print (read "34" :: a) 

Тогда в GHCI:

Data.Proxy *Main> foo (Proxy :: Proxy Double) 
34.0 
Data.Proxy *Main> foo (Proxy :: Proxy Int) 
34 

Или, более экзотическое использование, опираясь на более неявное поведении Haskell:

*Main> foo [0.0] 
34.0 
*Main> foo [0] 
34 
+0

'ScopedTypeVariables' - это то, что я хотел! Спасибо. – user3749167

+0

Обратите внимание, что вы можете сделать это без 'ScopedTypeVariables', например. define 'asProxyTypeOf :: a -> прокси a -> a; asProxyTypeOf = const', а затем напишите '' foo p = print (читайте «34» 'asProxyTypeOf' p)' '. – shachaf

+0

И с SignatureSections вы можете написать 'foo (:: Int) 34'. – augustss

4

Ни foo :: Double => IO(), ни foo :: Int => IO() не являются действительными сигнатурами, поскольку Double и Int не являются ограничениями.

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

foo :: (Read a, Show a) => IO a 
foo = let x = read "34" in print x >> return x 

Таким образом, вы можете использовать foo :: IO Double или foo :: IO Integer:

ghci> foo :: IO Double 
34.0 -- print 
34.0 -- result, you would discard it 
ghci> foo :: IO Integer 
34 
34 
+0

Извините, но это я не собираюсь делать. Тип должен быть 'IO()' – user3749167

+0

@ user3749167: Это легко фиксируется с помощью 'void (foo :: ...)'. Другим вариантом будет «ScopedTypeVariables», как сказал Дэниел. – Zeta

+0

Моя фактическая функция намного сложнее, и ее нельзя разрешить с помощью 'void'. Спасибо большое! – user3749167

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