воскресенье, 22 октября 2017 г.

Вопрос. Haskell

А кстати можно так написать?
h :: Int -> Int
h x + 1 = x

h 3 == 2

Правило вывода сработает?

Ну это я таким извращённым способом операцию декремента реализую. Теоретически.

Понятно, что можно написать напрямую:
h x = x - 1

но мне интересна внутренняя природа устройства правил вывода.

UPDATE. На вопрос я вроде бы нашёл ответ - в pattern matching'е участвуют не функции, а конструкторы. Поправьте, если я не прав.

41 комментарий:

  1. До hs2010 такие паттерны работали, потом их убрали из стандарта.
    А чем это поможет узнать внутреннею природу сопоставления с образцом в haskell?

    ОтветитьУдалить
    Ответы
    1. Это поможет понять масштаб "надувательства" под капотом.

      Ещё пример:

      Sqrt x * x = x

      Sqrt 9 == 3
      Сработает?

      Удалить
    2. Сопоставление с образцом нужно для разбора ADT на составляющие;
      [a] это тип с двумя конструкторами(в терминологии hs) a : [a] и a. Можно сделать свой List, он будет выглядеть так: data List a = List a (List a) | End
      Тогда map с pattern matching'ом для него будет выглядеть так:
      map' :: (a -> b) -> List a -> List b
      map' _ End = End
      map' f (List x xs) = List (f x) (map' f xs)

      P.S [a] это специальное название для типа 'список', нельзя называть свои типы используя квадратные скобки. А вот конструкторы могут выглядеть как операторы, но должны начинаться на ':'. Например:
      data List a = a :+ List a | End

      Удалить
  2. Понятно. Спасибо.
    Я примерно что-то так и думал. Что там где-то должны конструкторы участвовать.

    ОтветитьУдалить
    Ответы
    1. Конструкторы, но к императивному миру они отношения не имеют. В c++/java нет аналогичных конструкций

      Удалить
    2. Ой ну конечно...
      Те же самые конструкторы. ;)

      Удалить
    3. Ок. Как на C++ будет выглядить тип data List a = List a (List a) | End с аналогичными конструкторами?

      Удалить
    4. "Подвох" ведь заключается только в End.

      Но очевидно, что задача легко решается. Введением в каждом экземпляре ссылки на тип данных.

      Удалить
    5. Подвох в том, что конструкторы в haskell и в c++ это не аналогичные конструкции

      Удалить
    6. Однако реализованы они на c++
      Ага.

      Удалить
    7. С таким же успехом можно утверждать что конструкции js идентичны с конструкциями C++/Java/любого языка на котором реализован интерпретатор js. Это ни о чем не говорит.
      Понимание конструкторов hs как конструкторов c++ будет только мешать изучению языка.

      Удалить
    8. Поверьте, я понимаю отличия конструкторов Haskell и конструкторов C++. ;)

      Удалить
    9. И понимаю, что такое data MyEnum = One | Two | Tree.

      И чем оно отличается от enum в c++.

      Удалить
    10. Я даже сам такое реализовал в своих скриптах. Оказывается...

      Удалить
    11. И что такое data MyData = MyData Int.

      И что такое data MyData = MyData Int | NullValue.

      Удалить
    12. И даже понимаю что означает:

      data Patient = Patient { firstName :: String
      , lastName :: String
      , email :: String
      }

      Удалить
    13. Это как понимать отличия между теплым и мягким. =)

      Удалить
  3. Интересно, как на ваших скриптах будет, например: xs = 1 : map (*2) xs

    ОтветитьУдалить
    Ответы
    1. Имеете в виду:
      f x:xs = 1 : map (*2) xs
      ?
      Или я что-то не так понял?

      Удалить
    2. f x:xs = 1 : map (*2) xs

      Выглядит так:

      LIST FUNCTION f
      IN aList
      ANY VAR Head
      LIST VAR Tail
      aList .Split Head Tail
      LIST:Make 1 Map ( 2 * ) Tail
      >>> Result
      ;

      Удалить
  4. "xs = 1 : map (*2) xs" это "xs = 1 : map (*2) xs".

    main = print (take 10 xs)

    >>>[1,2,4,8,16,32,64,128,256,512]

    ОтветитьУдалить
    Ответы
    1. А ну тем более всё просто.

      Удалить
    2. Хороший пример генрации бесконечной последовательности.

      Весь день над ним думал.

      Не буду врать - сейчас на моих скриптах это "в лоб" не делается. Только через "хоккей" типа CaptureContext.

      Но я уже придумал как это сделать так же элегантно как и в Haskell.

      Реализую - напишу.

      Удалить
    3. На основе того, что написано тут:
      http://programmingmindstream.blogspot.ru/2017/10/haskell-vs-count.html?m=1

      Ваш пример у меня выглядит так:

      List def xs
      List:Make:
      1
      ( call.me ( 2 * ) List:Map )
      ; // List:Map

      Я честно скажу - не проверял, но должно сработать. Завтра проверю.

      Удалить
    4. А map разве не к отдельным элементам применяется? Как у вас степени двойки получаются?

      У меня только так получается:

      f n = n : f n * 2

      xs = f 1

      Удалить
    5. xs = 1 : map (* 2) (1 : map (* 2) (1 : map (* 2) (1 : map (* 2) (1 : map (* 2) [1]))))
      xs = 1 : map (* 2) (1 : map (* 2) (1 : map (* 2) (1 : map (* 2) [1,2])))
      xs = 1 : map (* 2) (1 : map (* 2) (1 : map (* 2) [1, 2, 4]))
      xs = 1 : map (* 2) (1 : map (* 2) [1, 2, 4, 8])
      xs = 1 : map (* 2) [1, 2, 4, 8, 16]
      xs = [1, 2, 4, 8, 16, 32]

      Удалить
    6. Не совсем очевидно. Попробую переосмыслить.

      Удалить
    7. В общем у меня это выглядит так:

      List def xs
      List:
      1
      ^@( call.me ( 2 * ) .List:Map )
      >>> Result
      ; // xs

      Удалить
    8. Даже вот так:
      List def xs
      1 :List: ^@( xs ( 2 * ) .List:Map )
      ; // xs

      Удалить
    9. Проверил. Работает.

      Не то чтобы я хотел написать своё подобие Haskell. Это - жалкие потуги были бы.

      Мне было интересно понять как это устроено. И опробовать на примере.

      Чтобы возможно начать применять Haskell обладая пониманием.

      Удалить
    10. UPDATE. На вопрос я вроде бы нашёл ответ - в pattern matching'е участвуют не функции, а конструкторы. Поправьте, если я не прав.

      Удалить
    11. Я протрассировал:

      xs = 1 : map (*2) xs

      По шагам.

      И вроде понял Как оно работает.

      Удалить
    12. Только в терминологии haskell xs это константа, а не функция(морфизм).
      Если говорить вашим языком, то паттерн матчинг(и деструктивное описание) это такая магия компилятора, которая генерируется по структуре ADT. Никакие конструкторы в императивном понимании тут не участвуют(конечно, можно генерировать подобную магию и по иперативным конструкторам, как например в scala; Но там конструктор подразумевает описание структуры. А в C++/delphi/java конструктор это функция для инициализации полей, так что это не полные аналоги)

      Удалить
    13. Ну да.
      Только никакая не магия. А вполне себе формальное сопоставление. Грубо говоря кортежей. Фактический кортеж сопоставляется с тем, который в паттерн матчинге записан.
      И после этого сопоставления и получаются "константы".

      Удалить
    14. Сопоставление с образцом это сопоставление с образцом, вот так новости :D

      Удалить
    15. Снобизм и щёконадувательство детектед...

      Удалить
    16. Офицер? Разве ирония == снобизм?

      Удалить
    17. Извините.
      Я попытался объяснить как я понял механизм паттерн матчинга.

      Удалить
    18. Извините пожалуйста ещё раз за наезд не по делу.

      Удалить
    19. Вы на самом деле мне ОЧЕНЬ ПОМОГЛИ. Я нашёл ОЧЕНЬ проблемную инверсию в своём императивном коде. СПАСИБО!

      Удалить
    20. ОЧЕНЬ ПОМОГЛИ со своим примером:

      xs = 1 : map (*2) xs

      Я начал его экстраполировать на свой императивный код и нашёл опрелелённые "дыры". Где была очень глубокая рекурсия при освобождении объектов и связанных с ними данных.

      СПАСИБО Вам!

      Нашёл ошибку, которую уже лет пять не мог поймать.

      Удалить