Делает ли -XStrict что-нибудь в GHC?

Я думал, что -XStrictдолжен был превратить GHC в Strict Haskell, поэтому я попробовал тест на бесконечную последовательность Фибоначчи.

my_zipWith f  x [] = []
my_zipWith f []  y = []
my_zipWith f (x:xt) (y:yt) = f x y : my_zipWith f xt yt

test_fibs n = 
    let fibs = 0 : 1 : my_zipWith (+) fibs (tail fibs) in
    take n fibs

main = do
        putStr $ show $ test_fibs 15

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

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.0.2

$ ghc -XStrict fibs.hs && ./fibs 
[1 of 1] Compiling Main             ( fibs.hs, fibs.o )
Linking fibs ...
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377]

Что я делаю не так?

Strict примерно добавляет аннотацию строгости ! везде, где она может быть добавлена ​​в ваш файл. Библиотеки, скомпилированные без этого флага, не затрагиваются. Здесь вы используете стандартный тип списка [a], который остается нестрогим. Если вы определили свой собственный тип списка (и связанные с ним zipWith, tail и т. д.), я думаю, вы получите ожидаемое поведение (?).
chi 24.12.2020 11:00

@chi Я понял это из ответа. Мне просто любопытно, можно ли сделать :, ++, zipWith и другие функции списка строгими.

MWB 25.12.2020 04:12

@MaxB: Нет, [] определяется как ленивый. Если вам нужны строгие версии базовых типов, есть Data.Strict.List.List от strict-base (хотя vector предпочтительнее) и пакет strict для некоторых других. У них есть экземпляры стандартных классов, таких как Foldable. zipWith не перегружен в base, но есть Zip в keys (отдельно от старого category-extras).

Jon Purdy 28.12.2020 22:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
218
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Strict прагма конечно позволяет GHC оценивать все строго, но только в Weak Head Normal Form. Например:

(a, b) = (error "a", error "b")

Если приведенный выше код существует в прагме Strict, возникает любая ошибка. Давайте посмотрим ваш код:

test_fibs n = 
    let fibs = 0 : 1 : my_zipWith (+) fibs (tail fibs) in
    take n fibs

fibs вызывается рекурсивно, но в списке минусов, так что теперь весь список WHNF. Вот почему ваш код не складывался.

Этот пост поможет и вам. Наслаждайтесь рекурсией и ленью!

Добавлять:

Простой способ использования deepseq:

{-# LANGUAGE Strict #-}
import Control.DeepSeq

my_zipWith f  x [] = []
my_zipWith f []  y = []
my_zipWith f (x:xt) (y:yt) = force $ f x y : my_zipWith f xt yt

test_fibs :: Int -> [Int]
test_fibs n = 
    let fibs = 0 : 1 : my_zipWith (+) fibs (tail fibs) in
    force $ take n fibs

main = do
        putStr $ show $ test_fibs 15

force определяется как force x = x `deepSeq` x, deepSeq глубоко буквально оценивает выражение до NF (нормальная форма). Это преобразование достигается с помощью GHC.Generics. Если конвертировать вручную, просто нужно оценить данные внутри, поэтому можно переписать следующее:

{-# LANGUAGE Strict #-}

my_zipWith f  x [] = []
my_zipWith f []  y = []
my_zipWith f (x:xt) (y:yt) = f x y : go
    where
        go = my_zipWith f xt yt

test_fibs n = 
    let
        fib2 = my_zipWith (+) fibs (tail fibs)
        fibs = 0 : 1 : fib2
    in
        take n fibs

main = do
        putStr $ show $ test_fibs 15

Но на самом деле они не могут складываться. Потому что GHC может обнаружить бесконечный цикл, но это уже другая история.

Так есть ли способ использовать строгие списки?

MWB 24.12.2020 05:20

Другие вопросы по теме