Haskell, уклоняющийся от вероятностных структур данных?

При поиске списков пропусков, реализованных в Haskell Вы не найдете многих. Это - вероятностная структура данных, бывшая нужная в генераторе случайных чисел, означая, что любая из этих структур должна была бы работать в монаде IO.

Люди Haskell избегают этих структур данных, потому что не возможно реализовать их просто? Как Haskell может иметь дело с ними?

19
задан pnuts 2 November 2015 в 22:36
поделиться

6 ответов

Я давно знал о CommandManager.InvalidateRequureRequested () и использовал его, но иногда это не работало для меня. Я наконец-то понял, почему это так! Даже если это не бросает, как некоторые другие действия, вы ДОЛЖНЫ вызвать его на главном потоке.

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

-121--884330-

Вы, безусловно, можете улучшить это решение, но я полагаю, что оно реализует упомянутый IComparer Ник.

public class Comparer : IComparer<string>
    {

      private Dictionary<string, int> _order;

      public Comparer()
      {
        List<string> list = new List<string>()
        {
            "CS01",
            "CS10",
            "CS58",
            "CS11",
            "CS71",
            "CS02",
            "CS55",
            "CS03",
            "CS70",
            "CS54",
            "CS60",
                 //<---How to prioritize any value that is not predefined in list to show up here?  such as 1234-444-555
            "CS57",

        };

        _order = new Dictionary<string, int>();
        for (int i = 0; i < list.Count; i++)
        {
          _order.Add(list[i], i);
        }
      }

      public int Compare(string x, string y)
      {
        //If either string is less than 4 characters, return the comparsion of the two strings
        if (x.Length < 4 || y.Length < 4)
          return x.CompareTo(y);

        string xPrefix = x.Substring(0, 4);
        string yPrefix = y.Substring(0, 4);

        int xSequence;
        int ySequence;
        if (_order.TryGetValue(xPrefix, out xSequence)
            && _order.TryGetValue(yPrefix, out ySequence))
        {
          // If both X and Y are in dictionary, return the comparison of the two
          return xSequence.CompareTo(ySequence);
        }

        if (_order.TryGetValue(xPrefix, out xSequence))
        {
          // If only X is in dictionary, x > y
          return 1;
        }

        if (_order.TryGetValue(yPrefix, out ySequence))
        {
          // If only y is in dictionary, x < y 
          return -1;
        }

        // otherwise return the comparison of the two 
        return x.CompareTo(y);

      }
    }

    private void button1_Click(object sender, EventArgs e)
    {

      textBox1.Text = textBox1.Text.Replace("(", "");
      textBox1.Text = textBox1.Text.Replace(")", "");
      string[] items = textBox1.Text.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
      Array.Sort<string>(items, 0, items.Length, new Comparer());
      textBox2.Text = String.Join(Environment.NewLine, items);

    }

При вводе

9988777
CS01 
1234444
CS11
77888999 

выводится:

1234444
77888999 
9988777
CS01 
CS11

One Major Pitfall here - при правильной сортировке предметов, если в списке имеется предмет длиной < 4 символа - например, при вводе 99 вместо 9988777 он не работает должным образом.

Чтобы решить эту проблему, необходимо четко определить, какой тип входных данных у вас будет.

-121--1948857-

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

С другой стороны, сокрытие нечистоплотного PRNG, вероятно, является оправданным использованием небезопасного PerformIO , как в ответе Ганеша Ситтампалама . Это вопиющим образом нарушает ссылочную прозрачность, но только в той степени, в которой PRNG вернет непредсказуемые, противоречивые значения - в чем вся точка! Однако по-прежнему требуется осторожность, поскольку компилятор может сделать неверные предположения относительно кода, поскольку он выглядит чистым.

Но на самом деле ни один из этих подходов ужасно привлекателен. Использование unsafePerformIO является неудовлетворительным и потенциально опасным. Многопоточность состояния PRNG проста, но накладывает (потенциально ложную) строгую последовательность на любые вычисления, которые его используют. Ни безопасность, ни лень не освобождаются легкомысленно программистами Haskell (и справедливо!), и, конечно, структуры данных, ограниченные IO , имеют ограниченную полезность. Таким образом, чтобы ответить на часть вашего вопроса, вот почему программисты Haskell, скорее всего, избегают таких структур.


Что касается «как Хаскелл может справиться с» такими вещами, я бы предположил, что это неправильный вопрос, чтобы задать .

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

Важно понимать, что алгоритмы и структуры данных являются средством, а не концом . Редко бывает, что требуется одна конкретная реализация - то, что требуется , как правило, является определенными характеристиками производительности . Поиск структур/алгоритмов данных, которые предлагают желаемые характеристики, в то же время будучи идиоматическим Haskell, почти всегда является лучшим планом, и, вероятно, будет работать лучше, чем пытаться запихнуть строгую императивную привязку в ленивую функциональную дыру.

Эта ошибка, пожалуй, наиболее часто встречается в подгруппе программистов, которые никогда не сталкивались с проблемой, которую они не могли решить с помощью хэш-таблицы, но привычка легко поддается многим из нас. Правильный подход заключается в том, чтобы перестать думать «как реализовать это решение в Haskell», а вместо этого «какой способ лучше всего решить мою проблему в Haskell» . Вы можете быть удивлены, как часто ответы отличаются; Я знаю, что часто бываю!

23
ответ дан 30 November 2019 в 02:29
поделиться

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

7
ответ дан 30 November 2019 в 02:29
поделиться

Можно контролировать ActiveMQ с помощью JMX . Это позволит вам увидеть, работает ли сервер, какие темы/очереди активны и много другой полезной информации.

-121--4434976-

Создал сценарий:

#!/usr/bin/env ruby
# Move unknown files in a Bazaar repository to the trash.
# 
# Author: Benjamin Oakes

require 'fileutils'

TRASH_DIRECTORY = File.expand_path('~/.Trash/')

stdout = %x(bzr stat)

within = false

stdout.each_line do |line|
  if line.match(/^unknown:$/)
    within = true 
    next
  elsif line.match(/^[a-z]+:$/i)
    within = false
    next
  end

  if within
    FileUtils.move(line.match(/^\s+(.*?)$/)[1], TRASH_DIRECTORY)
  end
end

Я только немного протестировал его, но, кажется, он работает просто прекрасно. Пожалуйста, дайте мне знать, если вы найдете проблему через комментарии.

Следует ли изучать sed и awk по отдельной теме? Я склонен писать эти вещи, используя ruby -e «некоторый код ruby» .

-121--3140544-

Случайные генераторы не требуют операций ввода-вывода . Они следуют своим собственным монадическим законам (происходящим от State monad) и поэтому могут быть представлены через Random monad.

В случае списка пропусков можно определить собственную монаду, способную выполнять вероятностные вычисления, или просто использовать стандартную Random .

demo :: Random Int
demo = do
 let l = SkipList.empty

 l2 <- l `add` ("Hello", 42)

 return $ l2 `get` "Hello"
3
ответ дан 30 November 2019 в 02:29
поделиться

Причинит ли это мне невыразимое горе, если я поставлю его в верхней части таблицы стилей?

Да. Вы больше не сможете работать с абсолютно позиционированными элементами, например - абсолютное позиционирование всегда будет относительно родительского элемента, что почти никогда не является желаемым результатом.

Я могу представить, что существует еще больше полей побочных эффектов z-индекса параметров настройки.

Не совсем хорошая идея ИМО.

И нет, позиция: статический не устарел, в конце концов, это установка по умолчанию:)

-121--1678483-

Проста поставка IP/имя узла удаленного компьютера в последовательность подключения к базе данных вместо localhost . Например:

jdbc:mysql://192.168.15.25:3306/yourdatabase

Убедитесь, что брандмауэр не блокирует доступ к порту 3306

Также убедитесь, что пользователь, с которым вы подключаетесь, может подключиться с этого имени хоста. Для сред разработки это безопасно с помощью 'имя _ пользователя' @ '%' . Проверьте руководство по созданию пользователя и руководство GRANT .

-121--1445114-

Во-первых, генератор случайных чисел в монаде ввода-вывода находится там для удобства. Можно использовать генераторы случайных чисел за пределами ИО монады; см. System.Random. Но, да, нужно поддерживать состояние; здесь полезна ST monad. И да, я бы сказал, что программист Хаскелл предпочитает чистые структуры данных.

1
ответ дан 30 November 2019 в 02:29
поделиться

Однажды я попытался реализовать список пропуска в Haskell. Конечно, это была неизменяемая структура данных (в конце концов, это Haskell). Но это означало, что необходимость в случайности отпала; «fromList» просто подсчитывал элементы и строил массивы пропусков нужной длины для каждого элемента (2 указателя на каждый 4-й элемент, 3 каждые 16-й, 4 каждые 64-й и т. д.).

В тот момент я понял, что просто строю более сложную версию дерева с гораздо меньшей способностью его видоизменять. Так что я сдался.

4
ответ дан 30 November 2019 в 02:29
поделиться

Списки пропуска могут быть реализованы чисто - просто инкапсулируйте текущий seed в состояние самого списка пропуска.

data SkipList a = SkipList StdGen (Node a)
data Node a = ...

Это может подвергнуть вас некоторым сложным атакам, которые не применимы против "настоящих" списков пропусков, поскольку вы можете прощупать вырожденные порядки вставки и атаки воспроизведения против одного и того же семени, но это позволяет вам получить преимущества структуры, когда использование противником не является проблемой.

Можно также прибегнуть к unsafePerformIO и тщательно продуманному интерфейсу, кажущемуся чистым с точки зрения побочных эффектов. Хотя, по общему признанию, он не является чистым внутри, интерфейс создает видимость чистоты.

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

12
ответ дан 30 November 2019 в 02:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: