← All posts tagged Haskell

А давайте спецолимпиадку по типам? Есть код codegists.com это Freer для стрелок, но с ним проблема, нужно квадратичное число инстансов, так надо определять Category (Freer Category eff), Category (Freer Arrow eff), несмотря на то, что Category => Arrow. Что очевидно очень печально, и хотелось бы это поправить.

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

gist.github.com

Есть чуть более простые варианты но с тоже с квадратичным числом инстансов, хоть и более простых. Так же можно запилить вариант на TH который будет сразу генерить полный instance search, но это читерство.

Принимаются варианты и предложения по улучшению гиста.

hPutStr :: Handle -> BL.ByteString -> IO ()
hPutStr hdl lbs = wantWritableHandle "Data.ByteString.Lazy.hPutStr" hdl $ \hdl__ ->
  BL.foldrChunks (go hdl__) (commit hdl__) lbs
 where
  go hdl__ (S.PS ps s l) rest = do
   unless (l == 0) $ withForeignPtr ps $ \p -> do
    _ <- bufWrite hdl__ (p `plusPtr` s) l True
    pure ()
   rest
  commit hdl__ =
   case haBufferMode hdl__ of
    BlockBuffering _   -> do return ()
    _line_or_no_buffering -> do flushWriteBuffer hdl__
                  return ()

amap :: (Category p, Strong p, Choice p, Profunctor p) => p a b -> p [a] [b]
amap = make . it . tasty where -- (p ||| amap p) where
  -- make :: Profunctor p => p (Either () (a,[a])) (Either () (b,[b])) -> p [a] [b]
  make = dimap view build
    where
     build = either (const []) (uncurry (:))
     view = maybe (Left ()) Right . uncons
  -- it :: (Choice p, Profunctor p) => p (a,[a]) (b,[b]) -> p (Either () (a,[a])) (Either () (b,[b]))
  it = right'
  -- tasty :: (Choice p, Category p, Strong p) => p a b -> p (a,[a]) (b,[b])
  tasty p = p ||| amap p
  (|||) x y = first' x >>> second' y

меняем it на right' и все перестает компилироваться, почему?

Prelude> let x = (id True, id undefined)
Prelude> :sprint x
x = _
Prelude> let x = (True, id undefined)
Prelude> :sprint x
x = _
Prelude> let x = (True, undefined)
Prelude> :sprint x
x = (,) True _
Prelude> let x = (True, undefined::Int)
Prelude> :sprint x
x = (True,_)
Prelude> let x = (True, False)
Prelude> :sprint x
x = (True,False)

кто-нить может мне объяснить почему вывод именно такой?

Хочу плагин к GHC, который вычисляет какие исключения может бросать функция. Причем, какой-нить тупой, ей даешь на вход текстовый файлик со списком:

Module.function : Module.Exception

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

haskell не для продакшена и нигде не используется.

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

Вот так неожиданно haskell оказывается в продакшенах, посмотрю код потом, может подробности расскажу.

давно не было haskell тут:

MAIN = go (replicate 100000000 1)
where
go [] = return ()
go xs0 =
let ~(xs, ys) = span (>0) xs0
in do print $ foldl' (+) 0 xs
go ys

вот такая программа, если запустить её прибивает OOM Killer.
меняем $ на $! и она работает в constant space.

Просмотр stg показывает совсем мало разницы, в падающем случае unboxed tuple возвращаемый span снова боксится:

let blabla = case GHC.List.$wspan lvl1_r71d wild_s71y of _ [Occ=Dead] {
(#,#) ww1_s71D [Occ=Once] ww2_s71E [Occ=Once] ->
(,) [ww1_s71D ww2_s71E];

в обычном просто дальше идёт код.

Так же в падающем варианте идёт ещё одна аллокация:

let {
sat_s71M [Occ=Once, Dmd=<L,1*U>] :: GHC.Base.String
[LclId, Str=DmdType] =
\s srt:SRT:[r2vu :-> GHC.Show.$w$cshowsPrec3, r71e :-> go_r71e] []
case ds1_s71B of _ [Occ=Dead] {
(,) xs_s71G [Occ=Once] _ [Occ=Dead] ->
... бла-бла-бла тут развернутый fold и show

я понимаю почему падающий жрёт больше, но я не понимаю почему это не больше на какой-то множитель, почему ничего не освободжается.

<rubber-duck-mode>
А как бы задавать неявные методы для решения ОДЕ, так чтобы пользователь мог задать стратегию решения?
После размышления, у меня ощущение, что если в явном методе я могу возвращать (в простом случае без доп структуры):
phi :: x -> f x -> f x
то для неявного я должен писать:
phi :: x -> (f x, f x) -> f x

где теперь мне на вход подается начальная координата и первое приближение, и в ответ я выдаю набор следующих координат. Вроде в этом случае вся свобода, которая должна быть остается в руках у пользователя, можно и начальное приближение удобным способом выбирать, и решать хочется ли fixed point или newton iteration или вообще заанролить метод на нужную глубину.
</rubber-duck-mode>