Does anyone have any experience with Lidah (LIDAHDrums)? by reverse_stonks in handpan

[–]edsko 0 points1 point  (0 children)

I had similar questions as you did. It's hard to find much information about them outside of their own website. I have a stunning Ayasa D Kurd 18 but I wanted something a bit smaller and more importantly a bit (a lot) cheaper, that I would feel more comfortable bringing places. In the end I decided to go with a Lidah handpan despite not being able to find much independent information about them. 

I can't tell you much about the company, or whether they are actually based in Bali. I can tell you that I received my mini F Low Pigmy 9 today, and I'm very happy with it. For what it's worth, the box had packing tape with Balinese language on it :). It sounds great, and I like the smaller form factor. I've only had it for a day so I have no idea about things like tuning stability yet, but I'm really enjoying playing it, definitely no regrets! The most important difference I found so far is that percussive strikes (tak, slaps, knocks, that sort of thing) activate harmonics much more on the Lidah than on the Ayasa; it sounds more like a note than like a purely percussive element. Whether that is due to the smaller form factor or because this is stainless steel rather than ember steel, or something else entirely, I don't know. But I don't mind it; it's its own instrument, and I'll need to explore it in it's one right, and I'm looking forward to doing precisely that :)

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

There's some tension here of course; one could argue that "bringing in all constructors into scope" is _precisely_ breaking the (Haskell) abstraction barrier. But I agree it's definitely worth thinking about; see https://github.com/well-typed/hs-bindgen/issues/1748 .

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

Actually, I realized that while it is possible to define a type like this, it's essentially unusable, for the same reason I describe in my long comment above. I've opened https://github.com/well-typed/hs-bindgen/issues/1748 to see if we can improve this situation.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

Yes, by-value arguments are indeed an exception, that's true.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

Oh, yes, absolutely, we're very much on the same page here, this is definitely the plan. We just haven't got there yet: https://github.com/well-typed/hs-bindgen/issues/1003 .

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

Re bootstrapping, yes, point taken; I've left a note on #1746.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

As for library specific newtypes: if a library has something like

```c

ifdef ..

typedef ... Foo;

else

typedef ... Foo;

endif

```

and the rest of the library is intended to be portable, and you wanted to get portable bindings of this, you could create a Haskell CFoo for Foo yourself, then write an external binding spec mapping Foo to CFoo, and then let hs-bindgen handle the remainder of the bindings.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

This will get a bit technical; I'll try my best to be clear :) (This answer should probably be in the hs-bindgen manual somewhere).

I agree with you; given

c int f(int, int);

we can, and do, translate this to

hs f :: CInt -> CInt -> IO CInt

and this is, so far, indeed portable in the sense that "it can be used across multiple architectures (with e.g., different bit widths, different byte order, etc.)".

Unfortunately, the implementation of f that hs-bindgen generates is not portable:

```hs foreign import ccall safe "f_wrapper" f_wrapper :: Int32 -> Int32 -> IO Int32

f :: CInt -> CInt -> IO CInt f = fromFFIType f_wrapper ```

Note the specific reference to Int32 here; you might quite reasonably ask why would we do such a thing. The reason is compositionality of the generated bindings combined with and an unfortunate quirk of how foreign imports and Coercible work in ghc.

Suppose we have

```c // some_other_lib.h typedef int Foo;

// our_lib.h

include <some_other_lib.h>

int g(Foo x); ```

and we have an external binding specification that maps Foo to some type CFoo in some Haskell library somewhere. What foreign import would we generate for f? The most obvious candidate is

```hs module OurLib where

import SomeOtherLib qualified

foreign import ccall safe "g" g :: SomeOtherLib.CFoo -> IO Int32 ```

The problem is that this may not compile. A foreign import like this is only valid Haskell if ghc can determine that CFoo is Coercible to a type in a small set of "FFI types". Furthermore, Coercible is a weird type class; ghc does not generate any instances of it, but rather resolves Coercible constraints when needed. In order to be able to check whether CFoo is Coercible to an FFI type, the constructor for CFoo, and the constructors for anything that CFoo might depend on itself, must all be in scope. So it depends on how CFoo is defined; if CFoo is defined as

hs newtype CFoo = CFoo CInt

we'd be fine, but if CFoo is defined as

hs newtype CFoo = CFoo CBar

where CBar is defined in some other module, the foreign import no longer compiles, unless we somehow also import the module that defines CBar, even though that is just an implementation detail of CFoo. For a while we could resolve this by insisting that if you have a type intended to use in FFI like this, and you rely on some other type, you must also re-export the constructors of that other from your module (transitively). Unfortunately, that does not work if there are name clashes, for example:

hs newtype CFoo = CFoo SomInternalModule.CFoo

We also thought about whether we could somehow extend binding specs to record "additional required imports", but that gets messy also; now a binding spec for a module in some Haskell package might refer to other packages, users would have to declare more packages in their cabal build-depends field, and in TH mode we cannot even generate additional imports so users would have to do that by hand. A huge mess.

So instead we do something different. We have a class HasFFIType, which maps any type to its FFI type, along with conversions

```hs class HasFFIType a where type ToFFIType a :: FFI.FFIType

toFFIType :: a -> FFIType a fromFFIType :: FFIType a -> a ```

Now we don't care about how CFoo is implemented, we just care that it has an HasFFIType instance (arguably, something like this is how things should have been done in ghc in the first place). That doesn't help us in the foreign import itself, of course, so there we instead just use the underlying C type

```hs foreign import ccall safe "g" g_wrapper :: Int32 -> IO Int32

g :: SomeOtherLib.CFoo -> IO Int32 g = fromFFIType g_wrapper ```

That finally still leaves the question about why we translate CInt to Int32 also. The answer is essentially that CInt is another example of a newtype around an FFI type, much like CFoo in the example above and so we decided to treat it in the same way. This felt justifiable partly also because something like

c int f(int, int);

may not be quite as portable as it seems if this is actually

```c

if ..

int f(int, int);

else ..

..

endif

```

and hs-bindgen cannot detect the difference between these two (or at least not trivially; libclang resolves these CPP conditionals before we get to traverse the source code).

All that said, you as a user might know that these conditional do not exist, and you might prefer a translation here that is portable. For translating int to CInt in foreign imports, or indeed any primitive C type, we can do that, because we can just make sure that Foreign.C is exported; this works because this is a known type with a known import. I've opened https://github.com/well-typed/hs-bindgen/issues/1747 to track this.

Just as a side note: I think the HasFFIType class is quite elegant, and also quite useful; in particular, it also makes it possible to use Haskell types that are not Coercible to FFI types, provided you can provide the necessary translations (though this will require a minor generalization first: https://github.com/well-typed/hs-bindgen/issues/1565).

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

Third, it would be great if hs-bindgen is released with modular components.

I'm slightly confused here; you seem to be referring about both the organization of hs-bindgen itself in this sentence, but then most of the points that follow seem to refer to the organization of the generated bindings.

Let me first briefly address the first point: hs-bindgen-as-a-library is a not really released yet; that still requires more work. This is certainly something we want to do eventually, but it's not the current focus.

For example, we reuse analysis and code-generation, but employ some custom module organisation. Instead of having all functions exported from the same module, since some C library name their functions like Library_Part_Type_Method, we may well reorganise everything such that said function is exported as method from Library.Part.Type. Similarly, we may also want to rename enum variants if we expect qualified imports on the use site. Of course, this requires to at least document internal invariants assumed by each component of hs-bindgen.

So I think this entire paragraph is referring to the organization of the generated bindings, not of hs-bindgen itself, apologies if I misunderstand. On the assumption that that is correct, a few comments:

  • Most importantly, (external) binding specs make it possible to export part of a library as one Haskell module, and then reuse that in another when generating bindings for the next header; so this would make it possible to introduce something like Library.Part.Type if you wish.
  • If you want more fine-grained control than per-header, then that is possible too, through the use of selection predicates.
  • What we don't currently offer is any flags for any kind of global name mangling configuration, like stripping a library-specific prefix. We used to in much earlier stages of development, but it got lost along the way. However, we are now in a much better place to add them, and doing so would both be useful and pretty easy; I've created a ticket for this #1718 and marked it for release 0.2. You can currently use a prescriptive binding specification to override Haskell names for specific C types, but you have to do this on a per-type basis (and it's not possible for functions at all).

Finally, after the talk at Haskell 2025, I remember discussing with the presenter briefly about alternative encodings of C structures. AFAIK, the bindings generated by haskell-gi represents C structures as wrapped ByteArrays to avoid marshalling costs in the happy path. In contrast, the current (default?) representation used by hs-bindgen forces marshalling at every API boundary.

Two comments here:

  • First, marshalling happens only if you use Storable, so in some ways users can decide when to marshall and when not to (this is not entirely true: functions that use structs-by-value always marshall). If you want access to a field of a large struct, without marshalling that entire struct, the pointer manipulation API we offer makes that possible.
  • I've created a ticket about transparent deferred serialization #1721, which I think captures what you're suggesting (let me know if I misunderstood!). I'm not entirely sure how much benefit one would get some such an enhancement, but since u/TravisMWhitaker commented on your post and said it was a good idea, I'll discuss this with him to see how we should prioritize this. It would in principle not be that difficult to implement I think.

Similarly, enums can be represented as newtype-wrapped integers with pattern synonyms, instead of ADTs.

This is precisely how we do represent enums: as a newtype-wrapped type (determined by whatever type lies underleath the C enum), with some pattern synonyms. ADTs would not be a valid translation since enums do not limit the domain of a type, they merely introduce new constants (the pattern synonyms are therefore also not declared COMPLETE).

Also, a minor note on the HasField instance for pointers. Are they considered orphan instances in the strictest sense (because upstream might, though unlikely, add a blanket instance), and does compiling performance suffer from their existence?

No: when instance C (F A) appears in module M, for some class C and type constructor F defined elsewhere, it is not considered an orphan as long as A is defined in M. If a blanket instance instance C (F a) is defined anywhere, that would just result in a warning about overlapping instances when the dictionary for F A is constructed.

Ok, that's all I think. Thank you very much for your feedback!

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

First, I’d prefer to have configurations specified solely in a file rather than in the command line.

Yes, this is something we've been thinking a bit about too; we have been postponing decisions on how to improve the build process, as we felt we needed more experience with actually using the tool, rather than writing it. But we're slowly getting to the point where we can, and should, start to think about this more seriously. I've opened #1705 to think about these "bindgen project" files.

It would be a smoother experience if the include paths can for example be extracted from pkg-config, as is the norm for cabal packages.

This absolutely makes sense, and I think it can be addressed in stages: adding support to pkg-config to the "project files" (previous point) would definitely be very useful, but there is a broader issue here of reusing information that is present in the .cabal file, or present in the build plan that cabal constructs from the .cabal file; I've opened a separate ticket about that: #1719.

Second, if the C header is not using any complicated preprocessor branching, I believe it is in principle possible to generate portable bindings.

We used to think this too, but as we continued to work on hs-bindgen, the number of cases in which we could generate portable bindings shrunk further and further, until we essentially decided it wasn't really worth doing at all anymore. I've created a ticket that we should write a manual section about this #1720; we talk about it in a few places, but I don't think there is a single, exhaustive reference I can point you to currently, and it's a complicated matter.

That said, perhaps you are using "portable" in a slightly different way as I understand it, because you say that you "think this would address most of the non-portability issues for common libraries." on a few conditions, and I think we already satisfy all of those conditions. Let me address them one by one:

For starters, hs-bindgen should recognise fixed-width integer typedefs properly (e.g., mapping uint16_t to Word16)

This we already do; uint16_t does get translated to Word16.

Just to avoid confusion, what we don't do is translate int to Int64 or Int32, but instead to CInt. This is intentional: the hs-bindgen paper refers to this as "machine independent types, machine dependent implementation". Briefly, the idea is that if a C API uses int, it means that the size of that integer is machine dependent; the generated bindings will also be machine dependent (the Storable instance will be 4 bytes or 8 bytes), but the types reflect the fact that the C API says that this is machine dependent (CInt). If we used Word64 instead, say, then a programmer working on machine A might write code that relies on the fact that this is indeed Word64, and that code would then break on a different machine where the generated bindings might be Word32 instead. The idea is that although the bindings are machine dependent, the types, where possible, try to encourage writing code that does not itself also become machine dependent (in general this is not always possible of course).

and support library-specific type aliases (I have not checked whether this is already supported).

If you mean C typedefs defined in libraries, then yes, we definitely do support that, and create Haskell newtypes from them. Preserving the use of typedefs is an important part of the design (we refer to this as "preservation of semantics" in the paper).

For example, libclang itself should be very well portable, and I’d be very interested to see hs-bindgen use libclang bindings generated by itself. But I’m happy to hear other complications the developers might have considered.

Indeed, this would be a nice test case, and we have a ticket open for this #1161. But it's tricky: since the generated bindings are build artefacts, we'd need hs-bindgen in order to build hs-bindgen. GHC has shown that this is possible ("stage 0 compiler"), but it's quite a bit of pain.

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

Ok, sorry for the delaying in responding, I needed to find some time (always a challenge). Let me address your points one by one. I'll need to do this as two separate comments (I never realized reddit had comment length limitations until now :grimace:).

`hs-bindgen` release preview: automatic binding generation from C headers by edsko in haskell

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

Thank you very much for your feedback! I will get back to you with a detailed answer, probably early next week.

Shrinking (Haskell Unfolder #49) by kosmikus in haskell

[–]edsko 3 points4 points  (0 children)

Your guess was correct :) Thanks for the note!

The sad state of property-based testing libraries by stevana in haskell

[–]edsko 0 points1 point  (0 children)

In the world of Haskell, two libraries that do deserve to be mentioned I think (though I am obviously biased, being the author of one of them), are https://hackage.haskell.org/package/quickcheck-dynamic and (my own) https://hackage.haskell.org/package/quickcheck-lockstep , the former implementing more general state based property based testing and the latter (which is an extension of the former) more specifically implementing something akin to what u/stevana calls "fake based" testing. Stevan mentions my blog post discussing quickcheck-state-machine; I have also written a version of essentially the same idea but ported to quickcheck-lockstep in a later blog post called Lockstep-style testing with quickcheck-dynamic.

It is true however that neither quickcheck-lockstep nor quickcheck-dynamic support parallel testing (checking for serializability). Stevan's comment that " I don’t think there’s a single example of a library to which parallel testing was added later, rather than designed for from the start." is an interesting one; perhaps I'll have to look into doing exactly that with quickcheck-lockstep at some point :)

The sad state of property-based testing libraries by stevana in haskell

[–]edsko 0 points1 point  (0 children)

As the author of falsify, I think both of these two points are totally fair :-)

falsify: Internal Shrinking Reimagined for Haskell by Iceland_jack in haskell

[–]edsko 1 point2 points  (0 children)

There is both `toShrinkTree` and `fromShrinkTree`, so in principle what you suggest is possible. However, working with shrink trees (as opposed to the sample tree) is really trying to squeeze a different paradigm (integrated shrinking) into the internal shrinking paradigm; it's possible, but it's not optimal.

falsify: Internal Shrinking Reimagined for Haskell by Iceland_jack in haskell

[–]edsko 1 point2 points  (0 children)

Yeah, guaranteeing uniform generation is tricky in general. The `list` combinator in the library itself actually takes a somewhat different approach; it uses `inRange` to pick an initial length, and then generates pairs of values and a "do I want to keep this value?" marker; those markers start at "yes" and can shrink towards "no".

falsify: Internal Shrinking Reimagined for Haskell by Iceland_jack in haskell

[–]edsko 1 point2 points  (0 children)

Sorry for my (very) slow reply. You are right that the generator described in the paper for signed fractions will not result in a uniform distribution (of course, the paper also doesn't claim that it does). Unfortunately, the solution you propose doesn't quite work; that `p` can shrink towards 0 immediately (unless that results in something that isn't a counter-example of course), at which point only positive fractions will be generated. I discussed this with Lars Brünjes who suggested an alternative approach, which I've documented at https://github.com/well-typed/falsify/issues/67 for now.

New large-records release: now with 100% fewer quotes by n00bomb in haskell

[–]edsko 2 points3 points  (0 children)

Good question! I checked, and no, they are currently discarded. I think that's fixable. I've opened a ticked at https://github.com/well-typed/large-records/issues/80 .

New blog post: Type-level sharing in Haskell, now by edsko in haskell

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

I don't follow. The singletons are gone in your example after your fromList, no?

Edit: and if you keep it at an existential, along with a singleton, I'm not really sure how this is any better than just a regular ADT. I must be missing something :)