LINUX.ORG.RU

Haskel. Преобразование типов.


0

1

Приветствую, джентельмены!

Вопрос: а как в Хаскеле сделать преобразование типов? к примеру, написать функцию, которая делала бы из Double Int

toInt :: Double -> Int ?

Или в принципе, как это делается?

Скажем, в результате деления (/) получается Fractional, который как Int (к примеру, в функции take) использоваться не может. Понимаю, что есть div, но это ведь частный случай. Как вообще в таких случаях поступают?


Ответ на: комментарий от anonymous

А можно с примерами? realToFrac -это как раз во Fractional а fromIntegral - это в Num

Что-то я не нашёл с ходу, как ими решить в своём вопросе

solom
() автор топика
Ответ на: комментарий от anonymous

Да, я понимаю - округление. Сорри, не упомянул в основном посте. А просто для интереса - чего-то низкоуровневого «на коленке» нет разве? Только функциями, описанными в Prelude ?

solom
() автор топика
Ответ на: комментарий от solom

Что-то я не нашёл с ходу, как ими решить в своём вопросе

Полиморфизм же.

round :: (RealFrac a, Integral b) => a -> b

Double это RealFrac, Int это Integral.

Macil ★★★★★
()
Ответ на: комментарий от solom

Это все ф-ии классов типов (или их композиции). На месте могут через низкоуровневые определяться, в зависимости от конкретных типов. Можно взять decodeFloat и преобразовать в Int руками. Только зачем?

anonymous
()

Только это не «преобразование типов», а просто функция ∷ Double → Int с заданным поведением. Преобразование типов тоже есть, но оно тебе не нужно.

anonymous
()
Ответ на: комментарий от dmfd

Ты не в тему: хотя бы «Double -> Int» привел как в оригинале. Если знать, что искать, то hoogle не нужен. В данном конкретном случае лучше Prelude посмотреть и иерархию числовых типов.

anonymous
()
Ответ на: комментарий от anonymous

Hoogle достаточно умён. В своё время я всякие truncate и fromIntegral нашёл именно через него, вбивая Float -> Integer.

dmfd
()
Ответ на: комментарий от dmfd

Hoogle достаточно умён.  — есть «слишком базовые» вещи и для него

fromIntegral

Свежо приданье: выводит лишь toInteger, все равно надо смотреть Prelude и увидеть, что эта ф-ия входит в fromIntegral.

anonymous
()
Ответ на: комментарий от anonymous

Я не говорил, что всё будет находиться в первой итерации, и не говорил, что остальные обитатели треда в чём неправы. Просто показал удобный способ поиска «того, не знаю чего». Что взъелся-то?

dmfd
()
Ответ на: комментарий от dmfd

Ибо больше на дешевый понт похоже.

«лучший друг», а потом чудесным образом «Real a => a -> Integer» заместо «Double -> Int»

удобный способ поиска «того, не знаю чего».

Но не в этом случае. Я лишь заметил, что это не лучший use-case для hoogle.

anonymous
()
Ответ на: комментарий от dmfd

К сожалению не подросток, а то мог у тебя адресок специалиста попросить.

// BTW, учитывая некоструктивность твоего поста, слив защитан, можешь больше не тужиться (ну разве что на местную публику поработать)

anonymous
()

Что я, собственно, хотел добавить ко всему сказанному выше. Что есть замечательный сервис под названием hoogle, который помогает найти функцию, не зная её названия, только по сигнатуре.

Твой запрос, фактически, заключается в поиске функции с сигнатурой Double -> Int. Или, учитывая всё сказанное выше, скорее (RealFrac a, Integral b) => a -> b. То есть это идеальный use-case данной поисковой системы.

Итак, я просто хотел поделиться полезным инструментом. Если мой тон показался вам высокомерным, или вы приняли эту скупую информацию как вызов, уточняю, что я ничего подобного не имел в виду.

dmfd
()
Ответ на: комментарий от solom

Мне хочется понять все эти процессы.

doubleToInt = round :: Double -> Int

при использовании же round непосредственно данная спецификация будет автоматически осуществляться компилятором всякий раз как будут выведены типы Double и Int для аргумента и результата соответственно.

Я в С не сталкивался с таким вот :)

В Си, к сожалению, нет ни параметрического, ни ad-hoc полиморфизма, ни модулей.

quasimoto ★★★★
()

Это довольно интересный вопрос. Сначала делаем вот так:

Prelude> :i Double 
data Double = GHC.Types.D# GHC.Prim.Double#
        -- Defined in `GHC.Types'
instance Enum Double -- Defined in `GHC.Float'
instance Eq Double -- Defined in `GHC.Classes'
instance Floating Double -- Defined in `GHC.Float'
instance Fractional Double -- Defined in `GHC.Float'
instance Num Double -- Defined in `GHC.Float'
instance Ord Double -- Defined in `GHC.Classes'
instance Read Double -- Defined in `GHC.Read'
instance Real Double -- Defined in `GHC.Float'
instance RealFloat Double -- Defined in `GHC.Float'
instance RealFrac Double -- Defined in `GHC.Float'
instance Show Double -- Defined in `GHC.Float'

Для начала нас должно заинтересовать что Double это Enum. Enum'ы это типы для которых есть succ и pred, что в нашем случае несколько странно может быть полезно. Смотрим:

Prelude> :i Enum 
class Enum a where
  succ :: a -> a
  pred :: a -> a
  toEnum :: Int -> a
  fromEnum :: a -> Int
  enumFrom :: a -> [a]
  enumFromThen :: a -> a -> [a]
  enumFromTo :: a -> a -> [a]
  enumFromThenTo :: a -> a -> a -> [a]
        -- Defined in `GHC.Enum'
instance Enum Ordering -- Defined in `GHC.Enum'
instance Enum Integer -- Defined in `GHC.Enum'
instance Enum Int -- Defined in `GHC.Enum'
instance Enum Char -- Defined in `GHC.Enum'
instance Enum Bool -- Defined in `GHC.Enum'
instance Enum () -- Defined in `GHC.Enum'
instance Enum Float -- Defined in `GHC.Float'
instance Enum Double -- Defined in `GHC.Float'

И видим, что преобразование Enum'а к Enum'у в общем виде сводится к:

toEnum . fromEnum

Но в нашем случае будет вполне достаточно fromEnum. Затем решаем что это какой-то странный способ и смотрим все остальные классы. И вот оно:

Prelude> :i RealFrac 
class (Real a, Fractional a) => RealFrac a where
  properFraction :: Integral b => a -> (b, a)
  truncate :: Integral b => a -> b
  round :: Integral b => a -> b
  ceiling :: Integral b => a -> b
  floor :: Integral b => a -> b
        -- Defined in `GHC.Real'
instance RealFrac Float -- Defined in `GHC.Float'
instance RealFrac Double -- Defined in `GHC.Float'

Различные функции округления.

Но если хочешь, ты можешь сериализовать Double в ByteString (или список Word8'ов) и преобразовывать как в C.

KblCb ★★★★★
()
Ответ на: комментарий от KblCb

сериализовать Double в ByteString (или список Word8'ов) и преобразовывать как в C

Можно сделать unsafeCoerce :: Double -> Int64:

> printf "%x\n" (unsafeCoerce 2.1 :: Int64)
4000cccccccccccd

и дальше по IEEE 754.

Или так:

        .text
foo:
        cvttsd2siq %xmm0, %rax
foreign import ccall foo :: Double -> Int64
quasimoto ★★★★
()

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

Gregon
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.