1 Востаннє редагувалося 221VOLT (20.12.2019 23:01:15)

Тема: haskell мітап, Львів

всім привіт!

запрошуємо на (2й) львівський haskell мітап

час та місце зустрічі --

захостити мітап погодилась компанія Ralabs,
адреса вул. Газова, 36/1 (це біля Форуму)

для охорони офісу просять
(підготувати список учасників) заповнити форму
https://forms.gle/CVdnMEbfPiodg9Mh8

неділя, 22 грудня, 13:00, вхід вільний :)

попередня тема цього мітапу:
"туторіал по монадах для новачків",
напевно, будуть обговорення різних алгоритмів,
цікавих задач та їх рішень, математичних теорій etc :)


чат львівського haskell мітапу в телеграмі
@lvivhaskell
https://телеґрам/lvivhaskell

анонс на dou
https://dou.ua/calendar/30492/

github репо
https://github.com/lvivhaskell

про попередню зустріч

перша зустріч відбулась 24 листопада, 13:00,
kredens cafe, вул. Порохова 20Д

тема зустрічі "знайомство з haskell для початківця",
розглянули декілька цікавих задач

слайди https://lvivhaskell.github.io/intro/slides.pdf

посилання на навчальні ресурси

книга Learn You a Haskell for Great Good! (en)
http://learnyouahaskell.com/chapters

курс Дениса Москвина по haskell (російською) на степіку
Подякували: leofun01, 0xDADA11C7, plusxx, fed_lviv4

2

Re: haskell мітап, Львів

А можна дізнатись, якою мовою будуть проходити обговорення? Бо я лише українську та англійську знаю.

Подякували: 0xDADA11C7, leofun01, koala, dot4

3

Re: haskell мітап, Львів

FakiNyan написав:

А можна дізнатись, якою мовою будуть проходити обговорення? Бо я лише українську та англійську знаю.

Я звісно не знаю точно, але

Прихований текст

https://i.gyazo.com/dcf3d1417e45215e355310ff4a2f3e67.png

Подякували: leofun01, dot2

4

Re: haskell мітап, Львів

дякую людям, які прийшли )

жаль, що дехто, хто був на першій зустрічі, цього разу не прийшов

Подякували: 0xDADA11C7, leofun012

5

Re: haskell мітап, Львів

dot написав:

Гескель.

Давайте так: кожен, хто придумує ще однин варіант транслітерації назви мови, пише програму на ній. Способів «правильного» перекладу/транслітерації можна придумати скільки-завгодно і двічі на рік міняти, але авторитетною може бути думка лише тих, хто справді використовує цей інструмент на практиці. Свою програму я вже написав був колись (і публікував тут на форумі, але не можу відшукати ту тему — схоже, з якихось незрозумілих міркувань її потерли, тому запощу ще раз).

Прихований текст
-- перетв. аргумент-число на запис числа китайськими ієрогліфами (utf-8)
-- https://en.wikipedia.org/wiki/Chinese_numerals
module Main where

toChinese :: Integer -> String
toChinese 0 = "零" -- або "〇"
toChinese 1 = "一"
toChinese 2 = "二"
toChinese 3 = "三"
toChinese 4 = "四"
toChinese 5 = "五"
toChinese 6 = "六"
toChinese 7 = "七"
toChinese 8 = "八"
toChinese 9 = "九"
toChinese x
 |x>=(10000^11) = toChinese2(x, (10000^11),"载")
 |x>=(10000^10) = toChinese2(x, (10000^10),"正")
 |x>=(10000^9)  = toChinese2(x, (10000^9), "涧")
 |x>=(10000^8)  = toChinese2(x, (10000^8), "沟")
 |x>=(10000^7)  = toChinese2(x, (10000^7), "穰")
 |x>=(10000^6)  = toChinese2(x, (10000^6), "秭")
 |x>=(10000^5)  = toChinese2(x, (10000^5), "垓")
 |x>=(10000^4)  = toChinese2(x, (10000^4), "京")
 |x>=(10000^3)  = toChinese2(x, (10000^3), "兆")
 |x>=(10000^2)  = toChinese2(x, (10000^2), "亿")
 |x>=10000 = toChinese2(x, 10000, "万")
 |x>=1000  = toChinese2(x, 1000,  "千")
 |x>=100   = toChinese2(x, 100,   "百")
 |x>=10    = toChinese2(x, 10,    "十")
 
toChinese2 :: (Integer, Integer, String) -> String
toChinese2 (x, n, symb)
 |x `mod` n == 0                    = toChinese(x `div` n) ++ symb
 |x `mod` n `div` (n `div` 10) == 0 = toChinese(x `div` n) ++ symb ++ "零" ++ toChinese(x `mod` n)
 |otherwise                         = toChinese(x `div` n) ++ symb ++ toChinese(x `mod` n)

main = do
    x<-getLine
    putStrLn(toChinese(read x :: Integer))
    
Подякували: 0xDADA11C7, 221VOLT, leofun013

6 Востаннє редагувалося 221VOLT (26.12.2019 06:49:57)

Re: haskell мітап, Львів

P.Y. написав:
Прихований текст
-- перетв. аргумент-число на запис числа китайськими ієрогліфами (utf-8)
-- https://en.wikipedia.org/wiki/Chinese_numerals
module Main where

toChinese :: Integer -> String
toChinese 0 = "零" -- або "〇"
toChinese 1 = "一"
toChinese 2 = "二"
toChinese 3 = "三"
toChinese 4 = "四"
toChinese 5 = "五"
toChinese 6 = "六"
toChinese 7 = "七"
toChinese 8 = "八"
toChinese 9 = "九"
toChinese x
 |x>=(10000^11) = toChinese2(x, (10000^11),"载")
 |x>=(10000^10) = toChinese2(x, (10000^10),"正")
 |x>=(10000^9)  = toChinese2(x, (10000^9), "涧")
 |x>=(10000^8)  = toChinese2(x, (10000^8), "沟")
 |x>=(10000^7)  = toChinese2(x, (10000^7), "穰")
 |x>=(10000^6)  = toChinese2(x, (10000^6), "秭")
 |x>=(10000^5)  = toChinese2(x, (10000^5), "垓")
 |x>=(10000^4)  = toChinese2(x, (10000^4), "京")
 |x>=(10000^3)  = toChinese2(x, (10000^3), "兆")
 |x>=(10000^2)  = toChinese2(x, (10000^2), "亿")
 |x>=10000 = toChinese2(x, 10000, "万")
 |x>=1000  = toChinese2(x, 1000,  "千")
 |x>=100   = toChinese2(x, 100,   "百")
 |x>=10    = toChinese2(x, 10,    "十")
 
toChinese2 :: (Integer, Integer, String) -> String
toChinese2 (x, n, symb)
 |x `mod` n == 0                    = toChinese(x `div` n) ++ symb
 |x `mod` n `div` (n `div` 10) == 0 = toChinese(x `div` n) ++ symb ++ "零" ++ toChinese(x `mod` n)
 |otherwise                         = toChinese(x `div` n) ++ symb ++ toChinese(x `mod` n)

main = do
    x<-getLine
    putStrLn(toChinese(read x :: Integer))
    

щиро вам дякую!

єдина людина, яка написала по темі, написала код
а не оффтоп)

7

Re: haskell мітап, Львів

Дякую 221VOLT і всім хто був на зустрічі за корисну інформацію.
Зараз я активно вивчаю Haskell, колись я його не довчив (можливо через високий поріг входження), тепер настав час завершити розпочате. І хоча до кінця навчання ще далеко, я вже бачу, що Haskell буде мати значний вплив на мої проекти.

Подякували: 221VOLT, 0xDADA11C7, ostap34PHP3

8

Re: haskell мітап, Львів

http://i.imgur.com/VdrpFAl.png
не знаю, про яку задачу тут говорили
https://replace.org.ua/post/51293/#p51293

але це прекрасна демонстрація того,
якими незручними є імперативні мови,
у яких немає паттерн матчингу


спочатку запишу в трох читабельнішому вигляді

((
  ($x != 1) || ($x != 2) || ($x != 3)
) && (
  $y != 2
))
?
(
  ($x != 4)
  ?
  (
    ($x != 5)
    ? 0 : 5)
  : 4
) : 1;

далі можна трішки спростити

// True && y /= 2 -> ...
// y /= 2 -> ...

далі цю функцію на haskell легко записати так

func x y
  | y == 2 = 1
  | x == 4 = 4
  | x == 5 = 5
  | otherwise = 0

або ж ще лаконічніше, отак

func2 _ 2 = 1
func2 4 _ = 4
func2 5 _ = 5
func2 _ _ = 0

8) Аве!

Подякували: 0xDADA11C7, leofun012

9

Re: haskell мітап, Львів

221VOLT написав:

далі цю функцію на haskell легко записати так
або ж ще лаконічніше, отак

Жахіття - це неможливо читати, втім, як і той код на імперативній мові. Якщо вам для того, щоб показати який крутий haskell треба взяти поганий код на імперативній, то ....

10

Re: haskell мітап, Львів

До речі, так, чому ви спрощення приписуєте Хаскелю? Я ще розумію, коли мова Wolfram Mathematica спрощує вирази чи мова Пролог виводить теорему, а тут інший випадок.

Подякували: 221VOLT1

11 Востаннє редагувалося 221VOLT (01.01.2020 14:08:38)

Re: haskell мітап, Львів

0xDADA11C7 написав:

До речі, так, чому ви спрощення приписуєте Хаскелю? Я ще розумію, коли мова Wolfram Mathematica спрощує вирази чи мова Пролог виводить теорему, а тут інший випадок.

паттерн матчинг робить код набагато лаконічнішим

func2 -- паттерн матчинг у чистому вигляді )

можливо, тут два різних терміни на купу --
спрощення, у розумінні математичному, з 5го класу школи (спростіть вираз ...)
спрощення, у розумінні -- потрібно менше коду писати

здається, я не приписував хаскелю
спрощення в математичному розумінні --
спочатку записав той же імперативний код з відступами,
далі відкинув частину булевого виразу, записавши у вигляді коментаря,
і аж після цього розпочався хаскель )

Подякували: leofun011

12

Re: haskell мітап, Львів

Yola написав:

Жахіття - це неможливо читати, втім, як і той код на імперативній мові.

що саме вам неможливо вчитати,
в функції func2 ?

func2 _ 2 = 1
func2 4 _ = 4
func2 5 _ = 5
func2 _ _ = 0

все максимально очевидно --
є два аргументи -- x та y,

паттерн матчинг працює зверху донизу --

спочатку перевіряється перша клауза --
якщо y == 2, то повертаємо 1, і байдуже, яким є x,

якщо перша кляуза не матчиться, перевіряється друга --
якщо x == 4, то повертаємо 4, і байдуже, яким є y

далі перевіряється 3я клауза,

остання клауза перевіряється, якщо жодна з попередніх не спрацювала,
в даному випадку в цій клаузі завжди повертається 0  :)

13

Re: haskell мітап, Львів

Не бачу особливої переваги вашого коду на Хаскелі над буйством тернарного оператора на С:

((y == 2) ? 1 : ((x == 4 || x == 5) ? x : 0))
Подякували: leofun01, 221VOLT, sensei3

14

Re: haskell мітап, Львів

0xDADA11C7 написав:

Не бачу особливої переваги вашого коду на Хаскелі над буйством тернарного оператора на С:

((y == 2) ? 1 : ((x == 4 || x == 5) ? x : 0))

:D мені навпаки -- оці дужечки мозок перегрівають,
без них -- прекрасно, в 1000 разів краще ))

15

Re: haskell мітап, Львів

Дужечки мозок перегрівають? Попрактикуйтеся з LISP'ом трохи))))))))))

Подякували: 221VOLT, leofun012

16

Re: haskell мітап, Львів

Yola написав:

Якщо вам для того, щоб показати який крутий haskell треба взяти поганий код на імперативній, то ....

Згідний, для демонстрації переваг мови програмування потрібні приклади якісного коду. Зараз я не готовий надати приклади такого коду на Haskell, але колись це станеться, і ми зможемо порівняти коди Haskell і C#.

Подякували: 221VOLT, Yola2

17

Re: haskell мітап, Львів

221VOLT написав:

все максимально очевидно --

Мені очевидно, що я не хотів би мати такий код ані на хаскелі, ані на тій імперативній мові. Він не читний. Не зрозуміло, що він робить, я не маю на увазі в математичному сенсі, а описово, в термінних доменної області. Такий код в проекті значно ускладнює підтримування.

Подякували: leofun011

18

Re: haskell мітап, Львів

leofun01 написав:

Зараз я не готовий надати приклади такого коду на Haskell, але колись це станеться, і ми зможемо порівняти коди Haskell і C#.

Не вірю ;)

Подякували: leofun011

19

Re: haskell мітап, Львів

leofun01 написав:
Yola написав:

Якщо вам для того, щоб показати який крутий haskell треба взяти поганий код на імперативній, то ....

Згідний, для демонстрації переваг мови програмування потрібні приклади якісного коду. Зараз я не готовий надати приклади такого коду на Haskell, але колись це станеться, і ми зможемо порівняти коди Haskell і C#.

C# з LinQ та предикатами не зовсім імперативна мова, краще чиста С.

Подякували: leofun011

20 Востаннє редагувалося leofun01 (04.01.2020 18:41:39)

Re: haskell мітап, Львів

0xDADA11C7 написав:

C# з LinQ та предикатами не зовсім імперативна мова, краще чиста С.

Приблизно те саме можна сказати про C

C з бібліотеками та вказівниками на функції не зовсім імперативна мова, краще Assembler.

Yola написав:

Не вірю ;)

Змушуєте мене діяти. Правильно робите.

Ось приклади функцій генерування перестановок елементів:

Haskell
permutations :: Eq a => [a] -> [[a]]
permutations [] = [[]]
permutations l = concatMap (p l) l where
    p :: Eq a => [a] -> a -> [[a]]
    p l x = map (x :) (permutations (filter (x /=) l))

тут рядки з типами даних не обов'язково вказувати, тому цей код можна записати і так

permutations [] = [[]]
permutations l = concatMap (p l) l where
    p l x = map (x :) (permutations (filter (x /=) l))

в інтерпретаторі виклик функції має такий вигляд

permutations [1 .. 4]
C# (скорочена версія)
public static List<P> GetAllPermutations(int length) {
    List<P> list = new List<P>();
    P p = new P(), init = p;
    do {
        list.Add(p);
        p = p.GetNextPermutation(length, (int l, int r) => l >= r);
    } while(p != init);
    return list;
}
public P GetNextPermutation(int maxLength, Order<int> match) {
    int[] a = ToArray();
    ApplyNextPermutation<int>(a, maxLength, match);
    int r = 0;
    for(int i = 0; i < _count; ++i)
        r |= a[i] << (i << _s);
    return new P(r ^ _mix);
}
public static void ApplyNextPermutation<T>(T[] a, int maxLength, Order<T> match) {
    int length = a.GetLength(0);
    if(length > maxLength) length = maxLength;
    int n = 0, i;
    while(++n < length && match(a[n - 1], a[n])) ;
    if(n < length) {
        for(i = 0; match(a[i], a[n]); ++i) ;
        T t = a[n];
        a[n] = a[i];
        a[i] = t;
    }
    for(i = 0; i < --n; ++i) {
        T t = a[n];
        a[n] = a[i];
        a[i] = t;
    }
}

і це навіть не весь код.

C# (робоча версія, можна запускати)
using System;
using System.Collections.Generic;
using StringBuilder = System.Text.StringBuilder;
using CultureInfo = System.Globalization.CultureInfo;

namespace PermutationsList {
    using P = Permutation;

    public delegate bool Order<in T>(T l, T r);

    class Permutation : IEquatable<P> {
        private readonly int _length;
        private readonly int[] _array;

        private Permutation(int length, int[] array) {
            _length = length;
            _array = array;
        }
        public Permutation(int length) {
            if(length < 0) throw new ArgumentException();
            _length = length;
            _array = new int[length];
            for(int i = 0; i < length; ++i)
                _array[i] = i;
        }

        public int this[int index] {
            get { return _array[index]; }
        }
        public int[] ToArray() {
            int[] a = new int[_length];
            for(int i = 0; i < _length; ++i)
                a[i] = _array[i];
            return a;
        }
        public P GetNextPermutation(int maxLength, Order<int> match) {
            int[] a = ToArray();
            ApplyNextPermutation<int>(a, maxLength, match);
            return new P(_length, a);
        }
        public P GetNextPermutation(int maxLength) {
            return GetNextPermutation(maxLength, (int l, int r) => l >= r);
        }
        public override string ToString() {
            StringBuilder sb = new StringBuilder();
            sb.Append("[");
            if(_length > 0) {
                int i = _length - 1;
                sb.Append(_length - _array[i]);
                for(--i; i >= 0; --i)
                    sb.AppendFormat(",{0}", _length - _array[i]);
            }
            sb.Append("]");
            return sb.ToString();
        }
        public override int GetHashCode() {
            int hash = _length;
            const int s = 32;
            for(int i = 0; i < _length; ++i) {
                int r = i % s;
                hash ^= _array[i] >> r;
                hash ^= _array[i] << (s - r);
            }
            return hash;
        }
        public override bool Equals(object obj) {
            return Equals(obj as P);
        }
        public virtual bool Equals(P other) {
            if(ReferenceEquals(other, null))
                return false;
            if(_length != other._length)
                return false;
            for(int i = 0; i < _length; ++i)
                if(this[i] != other[i])
                    return false;
            return true;
        }

        public static bool operator ==(P l, P r) {
            return ReferenceEquals(l, r) ||
                !ReferenceEquals(l, null) && l.Equals(r);
        }
        public static bool operator !=(P l, P r) {
            return !(l == r);
        }

        public static void ApplyNextPermutation<T>(T[] a, int maxLength, Order<T> match) {
            int length = a.GetLength(0);
            if(length > maxLength) length = maxLength;
            int n = 0, i;
            while(++n < length && match(a[n - 1], a[n])) ;
            if(n < length) {
                for(i = 0; match(a[i], a[n]); ++i) ;
                T t = a[n];
                a[n] = a[i];
                a[i] = t;
            }
            for(i = 0; i < --n; ++i) {
                T t = a[n];
                a[n] = a[i];
                a[i] = t;
            }
        }
        public static List<P> GetAllPermutations(int length) {
            List<P> list = new List<P>();
            P p = new P(length), init = p;
            do {
                list.Add(p);
                p = p.GetNextPermutation(length, (int l, int r) => l >= r);
            } while(p != init);
            return list;
        }
    }

    static class Program {
        static void Main(string[] args) {
            Console.Write("Enter length of permutation (int) : ");
            int length = int.Parse(Console.ReadLine(), CultureInfo.InvariantCulture);
            List<P> perms = P.GetAllPermutations(length);
            foreach(P p in perms)
                Console.WriteLine(p);
            Console.WriteLine();
            Console.WriteLine("Press enter to exit ...");
            Console.ReadLine();
        }
    }
}

Можливо ви скажете, що порівнювати ці 2 приклади не можна, бо в першому використана рекурсію, а в другому рекурсії нема. Ну то можете переписати останній приклад і використати рекурсію. Все одно код получиться більшим (ніж на Haskell) і можливо навіть менш читабельним.

Подякували: 0xDADA11C7, 221VOLT2