Haskell

jaror, in The Haskell Unfolder Episode 16: monads and deriving via
jaror avatar

For more details on DerivingVia, check out the paper:

https://ryanglscott.github.io/papers/deriving-via.pdf

Especially Section 4 which lists many use cases including the superclasses demonstrated in the video.

treeowl, in Introduce Yourself

I'm David Feuer. I maintain containers, co-maintain unordered-containers and pqueue, and contribute to various other projects. Data structures are fun. I'm a good person to talk to about laziness subtleties, and about whether particular applications of unsafe IO are safe in context.

jaror, in Haskell Interlude 41: Mike Angermann
jaror avatar

The discussion about incentives for stability was interesting. It reminded me of the maintainership standards proposal. I think it would be very useful to have Hackage show information like how quickly a package fixes version bounds when new versions of their dependencies are released.

jaror, in [Well-Typed] The Haskell Unfolder Episode 17: circular programs
jaror avatar

This was a fun episode. I was introduced to breadth first labeling and attribute grammars by Doaitse Swierstra at the Applied Functional Programming summer school in Utrecht. He was an inspiring figure.

The biggest disadvantage of circular programs is that it is very easy to get into infinite loops when you make mistakes. I wish there was an easy way to guarantee statically that circular programs are terminating (perhaps using types).

There is also a recent paper about implementing breadth-first traversals without relying on laziness: https://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/traversals.pdf. Unfortunately, that does not contain any benchmarks.

SageBinder,

@jaror Not sure if this is directly related to circular programs, but you may be interested in Aaron Stump’s work on DCS: https://gitlab.com/astump97/dcs/-/blob/main/talks/upenn-fall2023/upenn-talk.pdf?ref_type=heads

jaror, in [Well-Typed Blog] GHC activities report: August–September 2023
jaror avatar
jaror, in Defeating Return Type Polymorphism
jaror avatar

This gives a nice practical motivation for GADTs and existential quantification.

This existentials and GADTs can be converted into a CPS style without type equality constraints

That sounds interesting. I can't easily imagine what that would look like. Do you have an example?

BoydStephenSmithJr,
@BoydStephenSmithJr@hachyderm.io avatar

@jaror @bss03 Maybe I was wrong, but I think you can do Scott encoding of the GADT underneath the standard codensity representation of existentials via CPS. Still need higher-rank types, not "just" parametricity.

I should write up some code to check myself against GHC.

bss03, (edited )

I put this together this evening.


<span style="color:#323232;">{-# language GADTs #-}
</span><span style="color:#323232;">{-# language RankNTypes #-}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">import </span><span style="color:#323232;">Data.Functor.Const
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">-- The GADT
</span><span style="font-weight:bold;color:#a71d5d;">data </span><span style="color:#0086b3;">AGADT</span><span style="color:#323232;"> a </span><span style="font-weight:bold;color:#a71d5d;">where
</span><span style="color:#323232;">    </span><span style="color:#0086b3;">I </span><span style="font-weight:bold;color:#a71d5d;">::</span><span style="color:#323232;"> [</span><span style="color:#0086b3;">Integer</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">-> </span><span style="color:#0086b3;">AGADT Integer
</span><span style="color:#323232;">    </span><span style="color:#0086b3;">S </span><span style="font-weight:bold;color:#a71d5d;">:: </span><span style="color:#0086b3;">String </span><span style="font-weight:bold;color:#a71d5d;">-> </span><span style="color:#0086b3;">AGADT String
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">type </span><span style="color:#0086b3;">Scott_GADT</span><span style="color:#323232;"> a </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> forall fr</span><span style="font-weight:bold;color:#a71d5d;">.</span><span style="color:#323232;"> ([</span><span style="color:#0086b3;">Integer</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> fr </span><span style="color:#0086b3;">Integer</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> (</span><span style="color:#0086b3;">String </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> fr </span><span style="color:#0086b3;">String</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> fr a
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#795da3;">f </span><span style="font-weight:bold;color:#a71d5d;">:: AGADT </span><span style="color:#323232;">a </span><span style="font-weight:bold;color:#a71d5d;">-> String
</span><span style="color:#323232;">f (I x) </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">show x
</span><span style="color:#323232;">f (</span><span style="color:#0086b3;">S</span><span style="color:#323232;"> x) </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> x
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#795da3;">f' </span><span style="font-weight:bold;color:#a71d5d;">:: Scott_GADT </span><span style="color:#323232;">a </span><span style="font-weight:bold;color:#a71d5d;">-> String
</span><span style="color:#323232;">f' x </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">getConst </span><span style="font-weight:bold;color:#a71d5d;">$</span><span style="color:#323232;"> x (</span><span style="color:#0086b3;">Const </span><span style="font-weight:bold;color:#a71d5d;">.</span><span style="color:#323232;"> show) </span><span style="color:#0086b3;">Const
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">-- The Existential
</span><span style="font-weight:bold;color:#a71d5d;">data </span><span style="color:#0086b3;">AnyGADT </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> forall a</span><span style="font-weight:bold;color:#a71d5d;">. </span><span style="color:#0086b3;">MkAnyGADT</span><span style="color:#323232;"> (</span><span style="color:#0086b3;">AGADT</span><span style="color:#323232;"> a)
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">type </span><span style="color:#0086b3;">Scott_Any </span><span style="font-weight:bold;color:#a71d5d;">=
</span><span style="color:#323232;">  forall r</span><span style="font-weight:bold;color:#a71d5d;">.
</span><span style="color:#323232;">    (forall a</span><span style="font-weight:bold;color:#a71d5d;">.</span><span style="color:#323232;"> (forall fr</span><span style="font-weight:bold;color:#a71d5d;">.</span><span style="color:#323232;"> ([</span><span style="color:#0086b3;">Integer</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> fr </span><span style="color:#0086b3;">Integer</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> (</span><span style="color:#0086b3;">String </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> fr </span><span style="color:#0086b3;">String</span><span style="color:#323232;">) </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> fr a) </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> r) </span><span style="font-weight:bold;color:#a71d5d;">->
</span><span style="color:#323232;">    r
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#795da3;">g </span><span style="font-weight:bold;color:#a71d5d;">:: String -> AnyGADT
</span><span style="color:#323232;">g "foo" </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">MkAnyGADT</span><span style="color:#323232;"> (</span><span style="color:#0086b3;">I</span><span style="color:#323232;"> [</span><span style="color:#0086b3;">42</span><span style="color:#323232;">])
</span><span style="color:#323232;">g </span><span style="color:#183691;">"bar" </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">MkAnyGADT</span><span style="color:#323232;"> (</span><span style="color:#0086b3;">I</span><span style="color:#323232;"> [</span><span style="color:#0086b3;">69</span><span style="color:#323232;">])
</span><span style="color:#323232;">g x </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">MkAnyGADT</span><span style="color:#323232;"> (</span><span style="color:#0086b3;">S</span><span style="color:#323232;"> x)
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#795da3;">g' </span><span style="font-weight:bold;color:#a71d5d;">:: String -> Scott_Any
</span><span style="color:#323232;">g' "foo" x </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">x (</span><span style="font-weight:bold;color:#a71d5d;"></span><span style="color:#323232;">i _s </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> i [</span><span style="color:#0086b3;">42</span><span style="color:#323232;">])
</span><span style="color:#323232;">g' </span><span style="color:#183691;">"bar"</span><span style="color:#323232;"> x </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> x (</span><span style="font-weight:bold;color:#a71d5d;"></span><span style="color:#323232;">i _s </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> i [</span><span style="color:#0086b3;">69</span><span style="color:#323232;">])
</span><span style="color:#323232;">g' s x </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> x (</span><span style="font-weight:bold;color:#a71d5d;"></span><span style="color:#323232;">_i s' </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> s' s)
</span><span style="color:#323232;">
</span><span style="color:#323232;">main </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> interact (unlines </span><span style="font-weight:bold;color:#a71d5d;">.</span><span style="color:#323232;"> fmap x </span><span style="font-weight:bold;color:#a71d5d;">.</span><span style="color:#323232;"> lines)
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">where
</span><span style="color:#323232;">  x s </span><span style="font-weight:bold;color:#a71d5d;">= case</span><span style="color:#323232;"> g s </span><span style="font-weight:bold;color:#a71d5d;">of</span><span style="color:#323232;"> { </span><span style="color:#0086b3;">MkAnyGADT</span><span style="color:#323232;"> x </span><span style="font-weight:bold;color:#a71d5d;">-></span><span style="color:#323232;"> f x }
</span><span style="color:#323232;">  y s </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> g' s f'
</span>

You can swap out x for y to see the behavior is the same.

You can drop the GADT pragma, GADT definition, f, existential, g, and x (but keep all the Scott versions, includeing y) to reveal code that works “simply” with RankNTypes.

Higher-rank types and parametricity is quite powerful.

BTW, this isn’t new / doesn’t require the bleeding edge compiler. I’m on “The Glorious Glasgow Haskell Compilation System, version 9.0.2” from the Debian repositories.

jaror,
jaror avatar

The Lemmy->Kbin conversion has inserted a lot of <span> elements into your code making it unreadable. For people reading this from the Kbin side, here's the code:

{-# language GADTs #-}
{-# language RankNTypes #-}

import Data.Functor.Const

-- The GADT
data AGADT a where
    I :: [Integer] -> AGADT Integer
    S :: String -> AGADT String

type Scott_GADT a = forall fr. ([Integer] -> fr Integer) -> (String -> fr String) -> fr a

f :: AGADT a -> String
f (I x) = show x
f (S x) = x

f' :: Scott_GADT a -> String
f' x = getConst $ x (Const . show) Const

-- The Existential
data AnyGADT = forall a. MkAnyGADT (AGADT a)

type Scott_Any =
  forall r.
    (forall a. (forall fr. ([Integer] -> fr Integer) -> (String -> fr String) -> fr a) -> r) ->
    r

g :: String -> AnyGADT
g "foo" = MkAnyGADT (I [42])
g "bar" = MkAnyGADT (I [69])
g x = MkAnyGADT (S x)

g' :: String -> Scott_Any
g' "foo" x = x (\i _s -> i [42])
g' "bar" x = x (\i _s -> i [69])
g' s x = x (\_i s' -> s' s)

main = interact (unlines . fmap x . lines)
 where
  x s = case g s of { MkAnyGADT x -> f x }
  y s = g' s f'
bss03, (edited )

I think the spans are all syntax highlighting/coloring. Your comment seems to have a dangling ```/span at the end to me, but that might just be the KBin->Lemmy translation.

EDIT: Also, Lemmy seems to be munging this post between the preview and the submit, due to me wanting to include some text that appears to be a dangling xml/html end tag (angle brackets removed in edit for “readability”) inside backticks.

jaror,
jaror avatar

Ah, that's interesting. Although I can imagine not many people would want to write code in that style. And I also wonder how many languages support higher rank polymorphism in the first place.

bss03,

Yeah, I generally prefer pattern matching and constructor calls, but often languages don’t have GADTs or existentials. Even in GHC, existentials are still a bit “wonky”, though still generally nicer to use than CPS/Codensity.

jaror, in Haskell in Production: RELEX Solutions
jaror avatar

I'm always surprised by how much controversy there is online about laziness and space leaks, but almost all these industry interviews from Serokell includes lines such as:

Mats: Most of the things that people warn online such as laziness, memory leaks, hiring haven’t been problems so far. The biggest problem we have faced relates to upgrading the dependencies.

mangoiv, in Laziness in Haskell — Part 2: Why not Strict Haskell?
@mangoiv@functional.cafe avatar

@jaror second one was even more awesome than the first one! This view is something that makes it really possible to argue for laziness by default! Thank you @lexi_lambda!

Pipoca, in Laziness in Haskell — Part 1: Prologue

Semantically, eager languages are “strict”, while lazy languages are “non-strict”.

Strict means that f _|_ = _|_, that is to say, that passing an error value of any sort to a function must produce an error value. A lazy language is one where that isn’t a universal requirement.

So suppose we have a function like:


<span style="color:#323232;">genList 100 = error "too long"
</span><span style="color:#323232;">genList 0 = []
</span><span style="color:#323232;">genList x = x : genList (x - 1)
</span>

In a lazy language, you can have head (genList 1000) = 1000. In an eager language, it must be the case that head (genList 1000) = error “too long”, otherwise you’ve broken the semantics of the language. That requires actually evaluating the whole list.

That’s part of why laziness in strict languages has to be explicitly opt-in

mangoiv, in GHC 9.4.6 is now available
@mangoiv@functional.cafe avatar

@jaror this fixes my bug! Yeyyyy

jaror,
jaror avatar

Are you one of the lucky ones to find a segfault? :P

mangoiv,
@mangoiv@functional.cafe avatar

@jaror yes very nasty, I reported an issue and three bugs were found investigating it. Romes and Ben did great work doing so. It were multiple issues with pointer tagging.

mangoiv,
@mangoiv@functional.cafe avatar

@jaror it also exhibited a bug in the byte code interpreter which had been found before

underlap, in Introduce Yourself

I'm Glyn Normington. I dipped into Haskell briefly in about 2011, but recently got a little deeper into it when I taught a second year functional programming module at Winchester University, UK. I'm a retired programmer with 39 years experience and try to pass on some general tips in the module. I came here after recently deleting my Reddit account. (I've been on the Fediverse for a while as fosstodon.org/@underlap.)

kleidukos, in Introduce Yourself

I'm Kleidukos, interested in production Haskell, with a focus on developer experience, web services, accessibility and building community spirit. Glad to join the party here!

ThomasDuBuisson, (edited ) in Introduce Yourself

I'm "TomMD". To say I 'maintain' things might be an overstatement, but I've released a number of Haskell packages and minor fixes. Much of that was on my own but a significant portion were from my Galois days. I've had a few publications and am hoping to get to ICFP Seattle this year. Also years ago I made (cofounded) a company (Muse Dev) with Haskell as central part of the stack which was enjoyable.

Currently? Life is very busy so I'm just enjoying my Haskell time writing this and that rather than building much for release.

AphonicChaos, in Introduce Yourself

I'm Edwin. I've been enamored by Haskell for several years, but never had the opportunity to work on it professionally, or for any medium-to-large sized projects.

I did write a statistics calculator for DnD 5e for my DM that used Haskell for the backend though, and that was fun. I attempted to use Haskell for the GUI, but found the experience lacking, since my DM had a requirement that it work on Windows and be a desktop app. Long story short, I spent hours trying to get gi-gtk to work on Windows after spending other hours trying various other solutions (to include threepenny-gui) before eventually giving up and writing the GUI in Python + Qt 6.

I now have a passion project named "War Womb", which aims to be a 2D app that lets you play Warcaster: Neo-Mechanika digitally. I have a prototype written as a web-app using Python + FastAPI in the backend and Typescript + React on the frontened. I've been recently tinkering with SDL to see if I can treat the app more like a game, since there are a lot of interactive components, and thus hopefully use Haskell for this project instead, since I have way more fun programming in Haskell than anything else I've use.

jaror,
jaror avatar

Both projects sound cool! I've also experienced issues with GUI programming in Haskell. It seems once upon a time wx worked well, but now it is no longer maintained.

fgaz,

There's an ongoing effort to resurrect wxHaskell here

AphonicChaos,

Ooh. I'll take a looksie!

lomendil,
lomendil avatar

Thank you for posting that link!

AphonicChaos,

Ok, I took a look. The last comment was from more than a year ago, unfortunately. I think I got gtk to finally work. I just wish the gtk4 API changes hadn't forced a need to use implicit params :-(

fgaz,

The last comment is from last month. There's still a bit more to do but we're getting there

AphonicChaos,

Oof. Didn't realize GitHub messaged were threaded. I scrolled to the very bottom. Sloppy on my part, sorry

jaror, in TIL: wrapping list comprehension in a function can prevent fusion
jaror avatar

Stream fusion does work:

data Stream a = forall s. Stream !(s -> Step s a) !s
data Step s a = Yield a !s | Skip !s | Done

data Tup a b = Tup !a !b

cartesianProduct :: Stream a -> Stream b -> Stream (a, b)
cartesianProduct (Stream step1 s01) (Stream step2 s02) = Stream step' s' where
  s' = Tup s01 s02
  step' (Tup s1 s2) =
    case step1 s1 of
      Yield x s1' ->
        case step2 s2 of
          Yield y s2' -> Yield (x, y) (Tup s1 s2')
          Skip s2' -> Skip (Tup s1 s2')
          Done -> Skip (Tup s1' s02)
      Skip s1' -> Skip (Tup s1' s2)
      Done -> Done

eft :: Int -> Int -> Stream Int
eft x y = Stream step x where
  step s
    | s > y = Done
    | otherwise = Yield s (s + 1)

fooS :: Stream (Int, Int)
fooS = cartesianProduct (eft 0 10) (eft 0 10)

toList :: Stream a -> [a]
toList (Stream step s0) = go s0 where
  go !s =
    case step s of
      Yield x s' -> x : go s'
      Skip s' -> go s'
      Done -> []

foo :: [(Int,Int)]
foo = toList fooS
  • All
  • Subscribed
  • Moderated
  • Favorites
  • haskell
  • PowerRangers
  • hgfsjryuu7
  • Youngstown
  • khanakhh
  • slotface
  • rosin
  • InstantRegret
  • ngwrru68w68
  • kavyap
  • vwfavf
  • thenastyranch
  • DreamBathrooms
  • everett
  • magazineikmin
  • anitta
  • Durango
  • tacticalgear
  • mdbf
  • cisconetworking
  • ethstaker
  • GTA5RPClips
  • osvaldo12
  • cubers
  • modclub
  • tester
  • normalnudes
  • Leos
  • provamag3
  • All magazines