2014-02-16 3 views
2

Я хочу сделать функцию игрушку, которая производит Maybe a, а затем поднять show, чтобы сделать его Maybe String, но результат был странно для меня:Что делать различие между `: T` и пусть выражение в GHCi

λ> :t liftM show . Just 
liftM show . Just :: Show a1 => a1 -> Maybe String 
λ> liftM show . Just $ 10 
Just "10" 
λ> let f = liftM show . Just 
λ> f 10 

<interactive>:9:3: 
    No instance for (Num()) arising from the literal `10' 
    Possible fix: add an instance declaration for (Num()) 
    In the first argument of `f', namely `10' 
    In the expression: f 10 
    In an equation for `it': it = f 10 
λ> :t f 
f ::() -> Maybe String 
λ> let g = liftM show . Just :: (Show a) => a -> Maybe String 
λ> :t g 
g ::() -> Maybe String 
λ> let h = liftM show . Just :: Int -> Maybe String 
λ> :t h 
h :: Int -> Maybe String 

Я предполагаю, что это имеет какое-то отношение умозаключения типа, но я действительно не знаю, что случилось:

  • откуда это таинственное () взялось?
  • Почему GHCi не жаловался на двусмысленность?
+0

возможно дубликат [foldr против использования foldr1 в Haskell] (http://stackoverflow.com/questions/18661866/foldr-vs-foldr1-usage-in-haskell) –

ответ

7

Dum-duuum!

Следующая жертва dreaded monomorphism restriction.

Что происходит: для определения, которое выглядит как «постоянная переменная» (в том смысле, что могут использоваться и другие языки, т. Е. Не тип функции), например, f = ..., предполагается, что вы хотите на самом деле вести себя как константа (CAF, если быть точным). Это означает, что он не должен быть полиморфным, поскольку с параметрическим полиморфизмом в принципе есть дополнительный неявный аргумент функции (информация, которая должна быть типа a1).

Для достижения этой фактической константы, ghci defaults этот тип переменной относится к любому конкретному типу, который он считает наименее неуместным. Здесь единственным ограничением является Show; самый простой тип - ().

"правильный" способ обойти это, чтобы отключить ограничение мономорфизма:

Prelude>: набор -XNoMonomorphismRestriction
Prelude>: м + Control.Monad
Prelude Control.Monad> пусть f = liftM показать. Просто
Prelude Control.Monad> F 10
Just "10"

В качестве альтернативы, вы можете, как в реальном исходном файле вы всегда должны дать соответствующие подписи идентификаторам в GHCI:

Prelude Control.Monad> let g :: Показать a => a -> Maybe String; g = liftM показать. Просто
Prelude Control.Monad> г 10
Просто «10»

Делать это только на РИТ в = не работает, так как ограничение -мономорфизм умирает только после этого будет решен и по умолчанию (если, как и в h, в первую очередь нет переменных, потому что вы предоставили монографическую подпись для RHS).

Еще одно, что вы можете сделать, просто дать функции явный аргумент, тогда ограничение мономорфизма вообще не применяется. I.e., напишите его неточечно:

Контроль над прелюдией.Монада> пусть Ia = liftM показать $ Просто
Prelude Control.Monad> я 10
Просто "10"

+0

если бы я поместил 'NoMonomorphismRestriction' в мой' .ghci'? – Javran

+1

Не совсем. Хуже того, что это реально, некоторые вещи будут медленнее, потому что больше не существует полиморфных констант, но вряд ли это будет проблемой. – leftaroundabout

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