LINUX.ORG.RU

Haskell: конструктор списка


0

0

Есть бинарный файл, нужно выбирать из него 16-битные отсчёты с
определённого места (nBg - номер отсчёта в файле) и количеством-nSm.
Результат - список типа [Word16] (или [Int16]) размером nSm.

Вот последовательность действий над одним отсчётом (2-4):

1 main = do ff  <- decodeFile "Data.dat" :: IO [Word16]
2           let x1 = putWord16le (ff !! 10)
3               x2 = runPut x1
4               x3 = decode x2 :: Word16
5           printf "0x%x\n" x3

Здесь получаю 1 отсчёт. Нужно написать ф-цию, которая формирует
список из этих отсчётов, описанный выше. 
Примерная типизация:
getRecData :: IO a -> Integer -> Integer -> [a]
getRecData x nBg nSm

Здесь, x - значение возвращённое decodeFile (1 строка - ff, например)
nBg - номер позиции первого 16-битного отсчёта;
nSm - всего отсчётов;
[a] - результат, список отсчётов.
Использую a (IO a, [a]), т.к. может быть и Word8, Word16, Word32...

Нифига не понял, но такого типа, как у твоего getRecData не может быть, ибо из монады IO выхода нет (ну, если не использовать unsafePerformIO, а его надо использовать только в САМЫХ КРАЙНИХ СЛУЧАЯХ).

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

> Нифига не понял

Хм. Что не понятно ? Попробую ещё:

Бинарный файл. Данные в нём организованы в виде 16-битных слов (тип 
Word16), т.е. 0-15 бит 1-ый элемент, 16-31 2-ой и т.д. По-этому:
ff  <- decodeFile "Data.dat" :: IO [Word16]
Т.е. могу сейчас вычитать любой 16-ти битный элемент из этого файла:
  let x1 = putWord16le (ff !! NN)
      x2 = runPut x1
      x3 = decode x2 :: Word16
Здесь, в x3 находится NN-ый 16-ти битный эл-т.
Проверяю printf "0x%x\n" x3 - всё ОК.

Но, нужно создать ф-цию, которая бы таким образом вычитывала N 16-ти
битных эл-тов, начинающихся с позиции NN, и возвращающиюю список из
этих N 16-ти битных эл-тов, т.е. тип [Word16].

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

> Т.е. могу сейчас вычитать любой 16-ти битный элемент из этого файла:

Чего-то я всё равно не въезжаю... А чем просто ff !! NN плохо (без извращений с runPut и т.п.)?

> Но, нужно создать ф-цию, которая бы таким образом вычитывала N 16-ти битных эл-тов, начинающихся с позиции NN

Э-э-э... take N $ drop NN ff ?

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

> А чем просто ff !! NN плохо (без извращений с runPut и т.п.)?

Это, чтоб порядок следования байт поменять. Например, в файле число
AABB (16 бит), decodeFile вычитывает 0xAABB, а правильно - 0xBBAA,
т.к. у интела старший байт по старшему адресу. По-этому и использую
putWord16le и runPut. 
Слушай, нигде не могу найти - что значит знак $ в выражении ?

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

>> Слушай, нигде не могу найти - что значит знак $ в выражении ?

$ означает применение процедуры к аргументам:

f $ x = f x

Это чтоб не ставить лишние скобки в выражениях типа:

f a g b c h x y = f a $ g b c $ h x y = f a (g b c (h x y))

f и h- функции двух аргументов, g - трех

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

> Это, чтоб порядок следования байт поменять. Например, в файле число AABB (16 бит), decodeFile вычитывает 0xAABB, а правильно - 0xBBAA, т.к. у интела старший байт по старшему адресу. По-этому и использую putWord16le и runPut.

Э-м-м... тебя никогда не учили принципу KISS?

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

>> Но, нужно создать ф-цию, которая бы таким образом вычитывала N 16-ти битных эл-тов, начинающихся с позиции NN, и возвращающиюю список из этих N 16-ти битных эл-тов, т.е. тип [Word16].

Ну так а в чем проблема-то? Добавь рекурсивный вызов а-ля x3:func x y z (или как там в хаскеле, не помню уже), ну и счетчики передавай. Или можно аккумулятор передавать вида x3:rest, в чем загвоздка?

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

По ходу вопрос возник:

Как изменить значение переменной на какую-либо величину, например
инкрементировать (x1=x1+1, x1=x1+10 и т.д.) ? Когда так:

x1 = 3

main = do ....
          ....
          let x1 = x1 + 5


Происходит переполнение стэка. Получается рекурсия, как этого
избежать ?

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

>> Первое равенство неверно.

Это для наглядности ;)

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

Вот Miguel подсказал:

take N $ drop NN ff - просто и красиво. А с функцией, я думаю, проблематично будет...

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

>> let x1 = x1 + 5

В приличном обществе так не выражаются :))) Это ж функциональщина, тут такое не прокатит. А что мешает сделать так:

let x2 = x1 + 5

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

> Как изменить значение переменной на какую-либо величину

Никак. Такой вещи как "переменные" в Хаскеле нет.

(если кто начнёт возникать - убью).

> let x1 = x1 + 5

> Происходит переполнение стэка

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

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

> (если кто начнёт возникать - убью).

Шаман O_O deathwish-over-IP :D

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

Да, и чего тогда в доках по хаскелю пример инкремента приводят: ???

inc                :: Integer -> Integer
inc n              =  n + 1

Ведь всё равно не работает.

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

>Да, и чего тогда в доках по хаскелю пример инкремента приводят: ???

>inc :: Integer -> Integer inc n = n + 1

>Ведь всё равно не работает.

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

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

> а ты попробуй и убедись, что работает. 

Работает, но только так:

main = do let x1 = 3
              x2 = inc x1
          printf "%d\n" x2

А при x1 = inc x1 - не хочет. 
Как сделать x1 += 1; ?

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

>main = do let x1 = 3 x2 = inc x1 printf "%d\n" x2

>А при x1 = inc x1 - не хочет. Как сделать x1 += 1; ?

писать на другом языке. на кой ляд тебе вообще это "x1 += 1" нужно - можешь обьяснить ?

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

>Нельзя это сделать. Хаскел - чистый функциональный язык, не Ocaml какой-нибудь :)

а OCaml позволяет такое делать ? я был о нём лучшего мнения

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

>>Нельзя это сделать. Хаскел - чистый функциональный язык, не Ocaml какой-нибудь :)

>а OCaml позволяет такое делать ?

Насколько я понял из учебника, да.

> я был о нём лучшего мнения

Скажи честно: ты просто не знал, что Ocaml - не чистый функциональный язык, а гибридный :D

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

>Скажи честно: ты просто не знал, что Ocaml - не чистый функциональный язык, а гибридный :D

то, что он гибридный я знал, однако предполагал что это распространяется только на referential transparency - т.е. на возможность смешивать чистые функции и процедуры с побочными эффектами (тем же IO)

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

rotate из Data.Bits, если не хочется возиться с арифметикой.

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

>> Оно и должно на этом зависнуть.

> Понятно. Как избежать ?

Не делать этого.

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

> Как сделать x1 += 1; ?

Ещё раз тебе объясняю: забудь об этом. В Хаскеле НЕЛЬЗЯ менять однажды присвоенные значения.

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

> то, что он гибридный я знал, однако предполагал что это распространяется только на referential transparency - т.е. на возможность смешивать чистые функции и процедуры с побочными эффектами (тем же IO)

В ОКамле есть var (изменяемые переменные) и val (неизменяемые значения).

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

OK. Есть обработчик нажатия на кнопку (gtk2hs). Нужно считать количество нажатий на кнопку, т.е. кол-во вхожждений в обработчик. Как это сделать средствами хаскеля ?

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

> OK. Есть обработчик нажатия на кнопку (gtk2hs). Нужно считать количество нажатий на кнопку, т.е. кол-во вхожждений в обработчик. Как это сделать средствами хаскеля ?

IORef, монада State

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

Вот ещё такой способ проканал (замыкание, помоему):

inc :: Integer -> Integer
inc x = x1 + 1

x1 = 5

main = do ....
       x1 = inc x1

И нормально. Тока кривова-то конечно.

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

Слушай, после такого кода я вообще не понимаю, как ты умудряешься хоть что-то писать. Почитай учебник.

Хинт: после ЭТОГО значение (inc что-угодно) будет равно 6.

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

> Хинт: после ЭТОГО значение (inc что-угодно) будет равно 6.

Что и требовалось ;) А что криво, так я и сказал, так что не бузи!

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

Задумано сделать инкремент.
Сейчас вот так:

inc_x1 :: Integer
inc_x1 = x1 + 1

x1 инкрементируется, что и надо. Ты ж уже постов 10 никак не хочешь
сказать как правильно :),  сам пока просто ковыряюсь, пока вот так
получилось, буду дальше разбираться.

brahman
() автор топика

Вам не стоит браться за гуй на хаскелле пока не поймете что такое чисто функциональное программирование. Сейчас вы решаете задачу образом, который в хаскелле не предусмотрен by design. Либо зубрите учебник, либо двигайтесь в сторону стенки.

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

Слуш, а, может, он чужой исходник фиксит?

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

> Приходится императивные костыли вводить (do, монады)...

do - синтаксический сахар, монады - чисто функциональная вещь.

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

Не, ну монады это еще туда-сюда. По крайней мере если рассматривать их не как исключительно эмуляцию деструктивного присваивания, а как механизм реализации алгоритмов. Получается эдакий конвейер. А вот синтаксический сахар в виде do больше похож на маркетинговый ход создателей языка.

Мне вообще не очень понятно, почему язык называется "чистым функциональным" если в нем есть такая императивщина как do.

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

>Не, ну монады это еще туда-сюда. По крайней мере если рассматривать их не как исключительно эмуляцию деструктивного присваивания, а как механизм реализации алгоритмов. Получается эдакий конвейер. А вот синтаксический сахар в виде do больше похож на маркетинговый ход создателей языка.

именно как механизм реализации алгоритмов их и следует рассматривать. ну и как механизм проектирования (я бы сказал инкапсуляции) и автодокументирования кода (по типу функции всегда можно сказать - выполняет ли она IO, работает ли с состоянием, бросает ли исключения)

>Мне вообще не очень понятно, почему язык называется "чистым функциональным" если в нем есть такая императивщина как do.

do - это синтаксический сахад для работы с монадами. а монады, как было указано выше, используются не только (и не столько) для императивщины. хотя да, как показывает пример данного треда, do-нотация может быть трактована идиотически :(

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

>На голой функциональщине далеко не уедешь ;) Приходится императивные костыли вводить (do, монады)...

если ты не умеешь писать программы в функциональном стиле - зачем ты пишешь на Haskell ? пиши на OCaml, Scheme, CL - и пользуйся императивными методами в своё удовольствие. хочешь именно на Haskell - будь добр, освой хотя бы основы ФП

jtootf ★★★★★
()

/me, показывая язык

Можно писать mutable для полей структур и делать a := !a + 1;; когда захочешь. Но некоторые люди предпочитают трястись над своими халяльными монадами и думать по ночам, куда же еще впендюрить ленивые вычисления, чтобы GHC хоть для какой-нибудь школьной задачки шевелился быстрее рептилии. Одним словом, компутир сайнс.

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

>М-да... Вот так посмотришь на все это и понимаешь: do-нотация - ЗЛО!

скажем так - do-нотация небезопасна. свои плюсы в ней тоже есть - лично мне читать код, использующий do-нотацию для работы с монадами проще

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

>Можно писать mutable для полей структур и делать a := !a + 1;; когда захочешь

да пожалуйста, кто ж против-то ? на ассемблере вон вообще всё что хочешь можно :)

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