-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
No clear haskell API #2
Comments
What we can support without much further work is to set up a socket connection, to split incoming bytes into If we have that, we can decode |
I worked on this for a while but hit a few bumps. I sent a message to the haskell-cafe mailing list. So no real progress on this issue yet, but I just wanted to report having worked on it. |
Okay, since 3eab352 we can read XML data into a protocol object and process it into another object which can be used to track which wayland ID has which . I will now write code that generates this same data from a C pointer to a |
(TODO: reduce code duplication by parameterising whether the particular protocol flavor has the cross-references as |
(This TODO is now implemented by 72279ed.) |
I've started trying to write some client code that interfaces with a compositor in a rather "raw" form. main :: IO ()
main = do
s <- connectWithDefault
let fd = Fd $ fdSocket s
cliArgs <- getArgs
prot <- case cliArgs of
[] -> readProtocol
xmlLoc:_ -> parseFile xmlLoc
case prot of
Nothing -> die "Couldn't parse XML protocol"
Just prot' -> do
let get_registry = WireMessage 1 1 [WireArgBox SNewIdWAT 2]
get_registry_package = messageToPackage get_registry
bytes = wirePack get_registry_package
sendToWayland fd (BL.toStrict $ BB.toLazyByteString bytes) [] >>= print
return () It now seems to me that type safety must be the first step towards a Haskell API. In particular I'm thinking of using quasiquoting to be able to replace the explicit |
Over the past few months I've tried to think of an ideal haskell API. One thing that has been bugging me is that we can't "pass around" references to arbitrary wayland objects, as they might be invalidated later on: so we can't just pass the user code a So I'm starting to think we should only allow the user to specify how to handle the current tree of objects, and the various current modifications on it, rather than these objects being some kind of return value of a "get me the latest messages" request. In other words, we should have the user... fold (?) on the object tree? And then wayland messages are some kind of zipper (?) on that tree? Another element of this problem is the following. In most situations, user code will want to take the wayland point of view of the computer, and use changes of the wayland model to update some internal state: for example, if a new client connects to a compositor and creates a window (which means that the client sends a series of messages to the compositor), that means the compositor should now make space for the window on the screen, and present the user with ways to manipulate this new window, keep track of the window size and position, etc. That means that wayland state should cohere in some way with the internal state of user code (which may exist both compositor-side and client-side). Is there a way to present the wayland state so that it is easy for these two states in one piece of code to cohere in the right way? Or at least to make this state coherence testable? Ideas are very, very welcome. |
So more concretely, and at the same time more vaguely: in Haskell language, what is a stateful communication protocol? |
One possible definition is to say that the wayland state and the user code's state are both state transition systems. Then to say that the states cohere means something like that there is a bisimulation relation between them, with the bisimilar states being picked out by a state update function. Then one can also make sense of what it means for these states to update asynchronously. This is nice because we can now make precise mathematically what it means for wayland to be asynchronous, and there is hope we can test if it is true. The disadvantage is that we are going to have to be a whole lot more explicit about our states and their transitions. I'll try to write this up in some detail, although this might take a few weeks. |
Also, this is a really nice approach to making everything type safe. |
I will also read this and then write a proof of concept. |
Here's one attempt at encoding a #!/usr/bin/env stack
{- stack script
--resolver lts-12.2
--package vinyl
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedLabels #-}
import GHC.TypeLits
import Data.Vinyl
-- The type of messages display::error (see wayland.xml)
type DisplayError =
ElField ("displayerror" :::
FieldRec '["object_id" ::: Int, "code" ::: Word, "message" ::: String])
-- One sample message
err1 :: DisplayError
err1 = #displayerror =:
( #object_id =: 3
:& #code =: 18
:& #message =: "You sent the wrong message earlier, sorry!"
:& RNil
)
main = print err1 Result:
|
The advantage of the above approach over C's approach of generating appropriate function stubs is that it allows to write type-safe code that is generic in the actual message being sent. This is invaluable for writing debugging programs. A program may be written in the above style that is type-safe, even before the protocol is known: only at compile time (so crucially: after development time) does the protocol need to be decided. At the same time, if a programmer wishes to interact with a specific part of the protocol (e.g. interact with the mouse, because the programmer is writing a compositor), the above approach is a type-safe approach for exchanging messages. The messages can be stored as objects, and passed around freely - in contrast with C style messages which, from a libwayland user point of view, don't really exist as stand-alone objects. So I am to use this approach to allow users to write code that is independent of the protocol, yet is type safe in the sense that mistaking one message for another, or one message's argument for another, yields an informative compile-time error. |
Although the C client side is progressing steadily (reimplementing the C ABI), there is no clear API for haskellers to use.
The library should stay flexible, but that doesn't mean the API should be scattered around.
Perhaps writing example code will help steering the haskell API in the right direction.
Some of the code currently only existing for the C ABI (namely in the .CABI submodule) should be generalized for the entire Haskell API.
The text was updated successfully, but these errors were encountered: