From: Andre Nathan <andre@digirati.com.br>
To: caml-list@inria.fr
Subject: Re: [Caml-list] Encoding "links" with the type system
Date: Wed, 5 Oct 2016 16:46:56 -0300 [thread overview]
Message-ID: <8a4909ff-67dc-58c0-0974-1d35c8fce091@digirati.com.br> (raw)
In-Reply-To: <CAPFanBFNyaCx-1Fa54BZ2bGvo=9SPttbqQiEwkhbcS7AA2sqhw@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 3814 bytes --]
Hi Gabriel
This is an interesting way to derive the GADT, at least for me, as I
have never did any logic programming. The resulting API is a bit easier
to use than the one from Jeremy's idea, at least for my use case.
I'm using this idea to experiment with a type-safe SQL query builder,
which so far looks like this:
from Team.table
|> belonging_to Team.owner Here
|> having_one Project.leader Here
|> select
|> fields [field User.id; field User.name] (Next Here)
|> fields [field Team.id; field Team.name] (Next (Next Here))
|> fields [all Project.table] Here
This generates the following query:
SELECT
users.id, users.name,
teams.id, teams.name,
projects.*
FROM
teams
LEFT JOIN
users ON users.id = teams.owner_id
LEFT JOIN
projects ON projects.leader_id = users.id
I'm not sure if this will ever be of use in practice, as the Next/Here
stuff might be too complicated for users, but overall I'm quite happy
with the result and what I've learned, though of course it's far from
complete (e.g. no support for WHERE clauses).
Thanks for the hints!
Andre
On 09/30/2016 10:54 AM, Gabriel Scherer wrote:
> I came back to this thread thanks to Alan Schmitt's Caml Weekly News.
>
> Here is a fairly systematic approach to the problem, contrasting
> Jeremy's more virtuoso approach. It works well when the whole set is
> statically defined in the source code, but I'm not sure about more
> dynamic scenarios (when a lot of the type variables involved become
> existentially quantified.
>
> The idea is to first formulate a solution using logic programming. A
> link set can be represented as a list of accepted sinks, and I can write
> a small Prolog program, "insert" that takes a new link, and a link set,
> and traverses the link set to find the link's sink in the list, and add
> the link's source to the list in passing.
>
> set([sink]) :- link(source, sink).
> set(sinks) :-
> set(prev_sinks),
> link(source, sink),
> insert(prev_sinks, source, sink, sinks).
>
> (* either the sink we want to insert is first in the list *)
> insert([sink | _], source, sink, [source, sink | sinks]).
>
> (* or it is to be found somewhere, recursively, under some other sink
> [s] *)
> insert([s | prev_sinks], source, sink, [s | sinks]) :-
> insert(prev_sinks, source, sink, sinks).
>
> Once you have this logic program, it is straightforward to translate it
> to a GADT declaration:
>
> type 's linkset =
> | Init : ('source, 'sink) link -> ('source -> ('sink -> unit)) linkset
> | Insert : ('source, 'sink) link * 'set1 linkset * ('set1, 'source,
> 'sink, 'set2) insert -> 'set2 linkset
> and ('set1, 'source, 'sink, 'set2) insert =
> | Here : (('sink -> _) as 'set1, 'source, 'sink, 'source -> 'set1) insert
> | Next : ('set1, 'source, 'sink, 'set2) insert -> ('a -> 'set1,
> 'source, 'sink, 'a -> 'set2) insert
>
> let _ = fun (type t1 t2 t3) (lnk1 : (t2, t1) link) (lnk2 : (t3, t1)
> link) (lnk3 : (t3, t2) link) ->
> let set = Init lnk1 in
> let set = Insert (lnk2, set, Next Here) in
> let set = Insert (lnk3, set, Here) in
> set
>
>
> On Wed, Sep 21, 2016 at 8:50 PM, Andre Nathan <andre@digirati.com.br
> <mailto:andre@digirati.com.br>> wrote:
>
> Em 21 de set de 2016, às 19:22, Jeremy Yallop <yallop@gmail.com
> <mailto:yallop@gmail.com>> escreveu:
>> It is! Here's one approach, which is based on two ideas:
>
> Wow, there's a lot to digest here :) Most of it is new to me,
> including the use of "evidence" types... I'll have to re-read it and
> try to work it out after a night of sleep.
>
> Thanks,
> Andre
>
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
next prev parent reply other threads:[~2016-10-05 19:47 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-21 19:12 Andre Nathan
2016-09-21 22:22 ` Jeremy Yallop
2016-09-22 0:50 ` Andre Nathan
2016-09-30 13:54 ` Gabriel Scherer
2016-10-05 19:46 ` Andre Nathan [this message]
2016-10-05 20:15 ` Daniel Bünzli
2016-10-07 17:02 ` Shayne Fletcher
2016-10-08 21:51 ` Shayne Fletcher
2016-10-11 0:16 ` Jacques Garrigue
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8a4909ff-67dc-58c0-0974-1d35c8fce091@digirati.com.br \
--to=andre@digirati.com.br \
--cc=caml-list@inria.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox