Есть ли в Haskell бесконечность :: Num a => a?

Ниже приведен быстрый подход к удалению потенциала '\n' из строки, сохраненной в fgets(). Он использует strlen() с двумя тестами.

char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {

  size_t len = strlen(buffer);
  if (len > 0 && buffer[len-1] == '\n') {
    buffer[--len] = '\0';
  }

Теперь используйте buffer и len по мере необходимости.

Этот метод имеет побочное преимущество len значение для последующего кода. Это может быть быстрее, чем strchr(Name, '\n'). Ref YMMV, но оба метода работают.


buffer, из оригинала fgets() не будет содержать в "\n" при некоторых обстоятельствах: A) Линия был слишком длинным для buffer, поэтому только char, предшествующий '\n', сохраняется в buffer. В потоке остаются непрочитанные символы. B) Последняя строка в файле не заканчивалась символом '\n'.

Если на входе есть встроенные нулевые символы '\0' в нем где-то, длина, сообщенная strlen(), не будет содержать местоположение '\n'.


Некоторые другие ответы ' Проблемы:

  1. strtok(buffer, "\n"); не удаляет '\n', когда buffer - "\n". Из этого ответа - изменен после этого ответа, чтобы предупредить об этом ограничении.
  2. Следующие ошибки приводятся в редких случаях, когда первый char, прочитанный fgets(), является '\0'. Это происходит, когда ввод начинается со встроенного '\0'. Тогда buffer[len -1] становится buffer[SIZE_MAX] доступным к памяти, конечно, вне допустимого диапазона buffer. Что-то хакер может попытаться найти в глупости чтения текстовых файлов UTF16. Это было состояние ответа , когда этот ответ был написан. Позже не-OP отредактировал его, чтобы включить код, подобный проверке этого ответа на "".
    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
    
  3. sprintf(buffer,"%s",buffer); - неопределенное поведение: Ref . Кроме того, он не сохраняет никаких ведущих, разделяющих или завершающих пробелов. Теперь удален .
  4. [Редактировать из-за хорошего ответа ] Нет проблем с 1 лайнером buffer[strcspn(buffer, "\n")] = 0;, отличным от производительности, по сравнению с strlen(). Производительность при обрезке обычно не является проблемой, поскольку код вводит I / O - черную дыру процессорного времени. Если следующий код нуждается в длине строки или имеет высокую производительность, используйте этот подход strlen(). Иначе strcspn() является прекрасной альтернативой.

26
задан remdezx 10 October 2014 в 11:18
поделиться

6 ответов

Может быть, вам нужен тип Maybe?

data Infinite a = Infinite | Only a

затем напишите экземпляр Num для Num a => Infinite a с необходимыми числовыми правилами.

15
ответ дан 28 November 2019 в 06:16
поделиться

Попробуйте что-нибудь подобное. Однако, чтобы получить операции Num (например, + или - ), вам нужно будет определить экземпляр Num для Infinitable a типа. Точно так же, как я сделал это для класса Ord .

data Infinitable a = Regular a | NegativeInfinity | PositiveInfinity deriving (Eq, Show)

instance Ord a => Ord (Infinitable a) where
    compare NegativeInfinity NegativeInfinity = EQ
    compare PositiveInfinity PositiveInfinity = EQ
    compare NegativeInfinity _ = LT
    compare PositiveInfinity _ = GT
    compare _ PositiveInfinity = LT
    compare _ NegativeInfinity = GT
    compare (Regular x) (Regular y) = compare x y    

main =
    let five = Regular 5
        pinf = PositiveInfinity::Infinitable Integer
        ninf = NegativeInfinity::Infinitable Integer
        results = [(pinf > five), (ninf < pinf), (five > ninf)]
    in
        do putStrLn (show results)
7
ответ дан 28 November 2019 в 06:16
поделиться

Ну как насчет того! Оказывается, если вы просто наберете 1/0 , он вернет Infinity ! На ghci:

Prelude> 1/0
Infinity
Prelude> :t 1/0
1/0 :: (Fractional t) => t
Prelude> let inf=1/0
Prelude> filter (>=inf) [1..]

и затем, конечно, он работает вечно, никогда не находя числа больше бесконечности. (Но см. Комментарии ephemient ниже о фактическом поведении [1 ..] )

29
ответ дан 28 November 2019 в 06:16
поделиться

Если у вас есть граничные условия, которые иногда нужно проверять, а иногда нет, вы можете решить это следующим образом:

type Bound a = Maybe a

withinBounds :: (Num a, Ord a) => Bound a -> Bound a -> a -> Bool
withinBounds lo hi v = maybe True (<=v) lo && maybe True (v<=) hi
1
ответ дан 28 November 2019 в 06:16
поделиться
infinity = read "Infinity"
21
ответ дан 28 November 2019 в 06:16
поделиться

Посмотрите на мою библиотеку RangedSets, которая делает именно это в очень общем виде. Я определил тип "Boundary" так, что значение типа "Boundary a" всегда либо выше, либо ниже любого данного "a". Границы могут быть "AboveAll", "BelowAll", "Above x" и "Below x".

2
ответ дан 28 November 2019 в 06:16
поделиться
Другие вопросы по тегам:

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