Не могу понять почему в этом коде ambiguous type variable `a'
f :: Storable a => a -> (a, Int)
f x = (x, sizeOf (undefined :: a))
Обяъясните, пожалуйста.
Я считаю, что из контекста вызова f тип a должен быть выведен.
Здравствуйте, eks314, Вы писали:
E>E>f :: Storable a => a -> (a, Int)
E>f x = (x, sizeOf (undefined :: a))
E>
E>Обяъясните, пожалуйста.
E>Я считаю, что из контекста вызова f тип a должен быть выведен.
А чему же равен a?
Я в Хаскеле не силён, но почему бы не написать sizeOf x ?
Здравствуйте, eks314, Вы писали:
E>E>f :: Storable a => a -> (a, Int)
E>f x = (x, sizeOf (undefined :: a))
E>
Вам нужны
scoped type variables. Правильно будет так:
f :: forall a . Storable a => a -> (a, Int)
f x = (x, sizeOf (undefined :: a))
Здравствуйте, VoidEx, Вы писали:
VE>Я в Хаскеле не силён, но почему бы не написать sizeOf x ?
Верно, так вполне даже работает:
f x = (x, sizeOf x)
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, eks314, Вы писали:
E>>E>>f :: Storable a => a -> (a, Int)
E>>f x = (x, sizeOf (undefined :: a))
E>>
E>>Обяъясните, пожалуйста.
E>>Я считаю, что из контекста вызова f тип a должен быть выведен.
VE>А чему же равен a?
VE>Я в Хаскеле не силён, но почему бы не написать sizeOf x ?
Да, этот пример не самый подходящий. Я просто свел свой, немного более сложный код, к простому. В исходной задачи x — это возвращаемое значение функции.
Вот как это сейчас (без forall это не будет работать):
readFromFile :: forall a . Storable a => Handle -> IO a
readFromFile handle =
alloca readPtrFromFile
where
readPtrFromFile ptr =
let
bytesCount = sizeOf ( undefined :: a )
in do {
actualBytesRead <- hGetBuf handle ptr bytesCount;
assert (actualBytesRead == bytesCount) (peek ptr)
}
Здравствуйте, palm mute, Вы писали:
PM>Вам нужны scoped type variables. Правильно будет так:
PM>PM>f :: forall a . Storable a => a -> (a, Int)
PM>f x = (x, sizeOf (undefined :: a))
PM>
спасибо, помогло.
хотя я не понял логики этой проблемы. вроде ведь тип можно вывести на основании параметров. кажется, что это какие-то проблемы синтаксиса языка, хотя я понимаю, что вряд ли там все так тривиально.
Здравствуйте, eks314, Вы писали:
Правильно будет так:
PM>>PM>>f :: forall a . Storable a => a -> (a, Int)
PM>>f x = (x, sizeOf (undefined :: a))
PM>>
E>спасибо, помогло.
E>хотя я не понял логики этой проблемы. вроде ведь тип можно вывести на основании параметров. кажется, что это какие-то проблемы синтаксиса языка, хотя я понимаю, что вряд ли там все так тривиально.
Вы предположили, что вхождения "a" в строчках (1) и (2) должны обозначать одну и ту же переменную, но на самом деле для переменных типов таких правил видимости нет.
f :: Storable a => a -> (a, Int) -- (1)
f x = (x, sizeOf (undefined :: a)) -- (2)
GHC в вашем коде видит следующее:
f :: forall a1 . Storable a1 => a1 -> (a1, Int) -- (1)
f x = (x, sizeOf (undefined :: forall a2 . a2)) -- (2)
Никакой новой информации аннотация в строчке (2) компилятору не сообщила — он и так знал, что undefined имеет такой универсальный тип. Унифицировать переменные a1 и a2 причин нет — т.к. нет контекста, где бы
выражение с типом a1 использовалось бы в качестве a2.
Расширение scoped type variables вводит области видимости для переменных типов,
если они явно помечены ключевым словом forall.
Согласен, слово forall в GHC-Haskell перегружено и может сбивать с толку.
Здравствуйте, eks314, Вы писали:
E>Да, этот пример не самый подходящий. Я просто свел свой, немного более сложный код, к простому. В исходной задачи x — это возвращаемое значение функции.
E>Вот как это сейчас (без forall это не будет работать):
В рамках Haskell 98 можно выкрутиться так:
derefPtr :: Ptr a -> a
derefPtr = undefined
readFromFile :: Storable a => Handle -> IO a
readFromFile handle =
alloca readPtrFromFile
where
readPtrFromFile ptr =
let
bytesCount = sizeOf (derefPtr ptr)
in do {
actualBytesRead <- hGetBuf handle ptr bytesCount;
assert (actualBytesRead == bytesCount) (peek ptr)
}