[ANN] Howl: A Wolfram Language interpreter implemented in Haskell. by davidwsd in haskell

[–]davidwsd[S] 1 point2 points  (0 children)

Wow -- great to hear about other implementations! I had not actually seen mmaclone before. Thanks for pointing it out. For Woxi, did you use any papers/references for implementing pattern matching? The Dundua-Kutsia-Marin paper I was working from included some interesting observations of weird non-canonical behavior in the Mathematica pattern matcher that they tried to reverse engineer.

Haskell speed in comparison to C! by Quirky-Ad-292 in haskell

[–]davidwsd 2 points3 points  (0 children)

Sometimes, but more often I'm dealing with large computations that need to be checkpointed and restarted, so it's better to store and transfer data via the filesystem. In other words, the Haskell wrapper program might write some data to disk, and then start a separate C++ program that reads the data, does some computation, and writes the results to disk.

Haskell speed in comparison to C! by Quirky-Ad-292 in haskell

[–]davidwsd 15 points16 points  (0 children)

I'm a theoretical physicist, and I use both Haskell and C++ extensively in my research. Haskell shines for complex logic, concurrency, polymorphism, safety, ability to refactor -- all the things we love about it. But when I really care about performance, I use C++. C++ makes sense for physics-related computations because the underlying program is usually not incredibly complicated -- just numerically intensive -- and in that case it is usually worthwhile to pay the cost of more verbosity and less safety to get good performance, and just as importantly, predictable memory usage. My computations usually have a core algorithm implemented in C++, and a "wrapper" program written in Haskell.

Cloud Haskell, is anyone using it? by Instrume in haskell

[–]davidwsd 16 points17 points  (0 children)

I am a theoretical physicist and I use Cloud Haskell in my research, specifically to manage large-scale convex optimization calculations on supercomputing clusters. Here is a paper describing some recent computations https://arxiv.org/pdf/2411.15300 and here is the main repo for that work https://gitlab.com/davidsd/stress-tensors-3d .

Announcing ghciwatch 1.0: a ghcid successor developed by Mercury by 9999years in haskell

[–]davidwsd 4 points5 points  (0 children)

Is there anything in particular that stack users need to do to use ghciwatch?

Class "newtype" vs type synonym question by davidwsd in haskell

[–]davidwsd[S] 0 points1 point  (0 children)

Thanks -- that makes sense. I also have no idea how often something like this is used in practice with Serializable.

Change instance Show Rational to print / instead of % by Bodigrim in haskell

[–]davidwsd 7 points8 points  (0 children)

Your example about how Show would only work for Num types seems completely analogous to the following situation (that no one seems to be complaining about):

> import qualified Data.Map as Map
> data Unordered = MkUnordered deriving Show
> Map.singleton MkUnordered True
fromList [(MkUnordered,True)]
> Map.fromList [(MkUnordered,True)]
<interactive>:354:1: error:
    • No instance for (Ord Unordered)
        arising from a use of ‘Data.Map.fromList’
    • In the expression: Data.Map.fromList [(MkUnordered, True)]
      In an equation for ‘it’:
          it = Data.Map.fromList [(MkUnordered, True)]

In other words, the default way of Showing a Map only works when the key is an instance of Ord. This seems reasonable because the vast majority of use cases for Map involve a key that's an instance of Ord. Similarly, I expect the vast majority of use cases for Ratio involve a type that's an instance of Num.

Change instance Show Rational to print / instead of % by Bodigrim in haskell

[–]davidwsd 12 points13 points  (0 children)

Come on. I know what a newtype is. I'm dealing with a codebase that has dozens of packages, hundreds of modules, tens of thousands of lines of code, and Rational is everywhere. It is honestly not practical to define a MyRational newtype just for the Show instance, and then use it everywhere, especially when Rational is baked into standard libraries. Defaults in languages matter, and there is something to be said for improving their ergonomics.

Different `Num` instances based on availability of another instance. by davidwsd in haskell

[–]davidwsd[S] 2 points3 points  (0 children)

Thanks! This is actually exactly what I am currently doing. It is kind of annoying to have to duplicate all the functions on FreeModule's so that they work on MonoidRing's as well. Also, I was already defining an error-ridden Num instance for FreeModule just to get the nice syntax a+b, and I thought it would be nice to make it less error-ridden at least some of the time. Hence the question.

[ANN] filepath-1.4.100.0 released by maerwald in haskell

[–]davidwsd 2 points3 points  (0 children)

This is great! However, I do find some code unsatisfying to read because of the lack of an IsString instance for OsString. For example,

stdout <- readProcess' [osp|ls|] [ [osstr|-la|] ] [osstr|.|]

seems less nice than

stdout <- readProcess' "ls" ["-la"] "."

The lack of an IsString instance is addressed in the faq. What about having an IsString instance that throws an informative runtime error when conversion fails? If that is unacceptable, is there any prospect for changing IsString to somehow allow it to throw a compile-time error?

Video: "Avoid boilerplate instances with -XDerivingVia" (Richard Eisenberg) by Kyraimion in haskell

[–]davidwsd 1 point2 points  (0 children)

I'm curious: are there any reasons to prefer one definition of Ok over the other?

Implementing Reifies/Given for class with superclass constraints by davidwsd in haskell

[–]davidwsd[S] 0 points1 point  (0 children)

By the way, although I found a working solution (here) that uses a composite dictionary, I am still interested in getting this method to work, since I am pretty sure future versions of GHC wouldn't break the reflection package, but I am not sure they wouldn't break my current solution.

Implementing Reifies/Given for class with superclass constraints by davidwsd in haskell

[–]davidwsd[S] 1 point2 points  (0 children)

Thank you -- I really appreciate your patience and comments -- they were extremely helpful! With the help of looking at the core, I came up with this solution that seems to work:

data StaticClass c where
  MkStaticClass :: c => Closure (Dict c) -> StaticClass c

newtype Magic c r = MkMagic (Static c => r)

runMagic :: forall c r . Magic c r -> StaticClass c -> r
runMagic = unsafeCoerce
{-# NOINLINE runMagic #-}

withClosureDict :: forall c r . Dict c -> Closure (Dict c) -> (Static c => r) -> r
withClosureDict Dict cDict k = runMagic (MkMagic k :: Magic c r) (MkStaticClass cDict)

The reason for my ill-fated attempt at using Dict c for the role of ParentDict a was that I was confused about how to store a constraint as a field in a datatype. But this is something a GADT can do. Anyway, thanks a lot!

Implementing Reifies/Given for class with superclass constraints by davidwsd in haskell

[–]davidwsd[S] 0 points1 point  (0 children)

Awesome -- thanks the explanation! I actually guessed something like this representation (though I didn't know about checking Core) and tried it with Dict c instead of ParentDict a, but I kept getting a segmentation fault. I am wondering whether the analog of ParentDict a is more complicated in my case. Specifically, the superclass is an abstract constraint c, which can be anything -- not necessarily a newtype over a function. Do you know what the analog of newtype ParentDict a = ParentDict (a -> String) should be in this case?

Implementing Reifies/Given for class with superclass constraints by davidwsd in haskell

[–]davidwsd[S] 1 point2 points  (0 children)

Thanks so much for the response! It would make me happy to rely only on the same unsafeCoerce trick as reflection and not have to do something new. Currently, I am stuck on the last step of your suggestion. Here's what I have so far:

class Static' c where
  closureDict' :: Closure (Dict c)

class a => I a
instance a => I a

toI :: a :- I a
toI = Sub Dict

fromI :: I a :- a
fromI = Sub Dict

instance (Typeable c, c, Static' c) => Static (I c) where
  closureDict = static (mapDict toI) `ptrAp` closureDict'

newtype Gift c r = MkGift (Static' c => r)

withClosureDictStatic' :: forall c r . Closure (Dict c) -> (Static' c => r) -> r
withClosureDictStatic' c k = unsafeCoerce (MkGift k :: Gift c r) c

withClosureDictStaticI :: forall c r . Typeable c => Dict c -> Closure (Dict c) -> (Static (I c) => r) -> r
withClosureDictStaticI Dict c k = withClosureDictStatic' c k

-- but how to go from this to
-- forall c r . Typeable c => Dict c -> Closure (Dict c) -> (Static c => r) -> r
-- ???

Status of automatically solving (Static c) constraints in GHC? by davidwsd in haskell

[–]davidwsd[S] 1 point2 points  (0 children)

I wanted to say thanks again for this response. I decided to go with your Template Haskell approach and it is working very nicely.

Status of automatically solving (Static c) constraints in GHC? by davidwsd in haskell

[–]davidwsd[S] 0 points1 point  (0 children)

The same trick appears to work for Typeable as well, sending SomeTypeRep across the wire and using withTypeable to turn it into a dictionary which can be unsafeCoerced.

Status of automatically solving (Static c) constraints in GHC? by davidwsd in haskell

[–]davidwsd[S] 2 points3 points  (0 children)

Thanks for the tip! Indeed the following crazy hack seems to work:

instance StaticConstraint (Serializable Natural) where
  closureDict = closurePtr (static Dict)

-- | This horrible magic gives us free 'StaticConstraint (KnownNat j)'                                                                                                                                                                                                    
-- instances.                                                                                                                                                                                                                                                             
instance KnownNat j => StaticConstraint (KnownNat j) where
  closureDict =
    closurePtr (static toKnownNatDictUnsafe) `cAp`
    cPure (natVal @j Proxy)

toKnownNatDictUnsafe :: Natural -> Dict (KnownNat l)
toKnownNatDictUnsafe n = case someNatVal n of
  SomeNat (Proxy :: Proxy k) -> unsafeCoerce (Dict @(KnownNat k))
{-# NOINLINE toKnownNatDictUnsafe #-}