73 lines
2.2 KiB
Markdown
73 lines
2.2 KiB
Markdown
# Cow Description Language (CDL)
|
|
In times of the pandemic, it's not easy to get real input data from your cows to
|
|
demonstrate the functionality of your front end. To be able to test some
|
|
features of the application, we would like to have scripts that
|
|
insert fake data points into our database, allowing us how our app
|
|
would behave in real time, without the need to hook up any collars.
|
|
These scripts would be tedius to write...
|
|
|
|
Unless, of course, you have a Domain Specific Language (DSL) for it!
|
|
Enter CDL. We can describe a cow in a turtle-style imperative language:
|
|
|
|
```Haskell
|
|
squareCow = do
|
|
move 10
|
|
turn 90
|
|
move 10
|
|
turn 90
|
|
move 10
|
|
turn 90
|
|
move 10
|
|
```
|
|
|
|
This DSL is shallowly embedded into Haskell, which means that we can
|
|
use all of Haskell's abstraction capabilities:
|
|
|
|
```Haskell
|
|
repeat 0 _ = return ()
|
|
repeat n thing = do
|
|
thing
|
|
repeat (n-1) thing
|
|
|
|
squareCow = repeat 4 $ do
|
|
move 10
|
|
turn 90
|
|
```
|
|
|
|
Given a sampling frequency, CDL can generate a Python script that
|
|
inserts data points into our database each "sample":
|
|
|
|
```Python
|
|
from server.fgs.model import *
|
|
from server.fgs import db
|
|
import datetime
|
|
db.session.add(DataPoint(longitude=0.0, latitude=0.0, datetime=datetime.now()))
|
|
db.session.commit()
|
|
sleep(0.1)
|
|
db.session.add(DataPoint(longitude=9.0000094e-7, latitude=0.0, datetime=datetime.now()))
|
|
db.session.commit()
|
|
sleep(0.1)
|
|
db.session.add(DataPoint(longitude=1.8000019e-6, latitude=0.0, datetime=datetime.now()))
|
|
db.session.commit()
|
|
sleep(0.1)
|
|
# ...
|
|
```
|
|
|
|
To generate scripts, load the program into GHCI and execute as follows:
|
|
```
|
|
cd src
|
|
ghci
|
|
:load Cdl/SampleCows.hs Cdl/Codegen.hs Cdl/Cow.hs
|
|
:module Cdl.SampleCows Cdl.Codegen Cdl.Cow
|
|
outputCow "test.py" 0.1 (1, 1, Coord 0 0, squareCow)
|
|
```
|
|
|
|
In `outputCow`, the `0.1` is the sampling frequency (how often
|
|
the database will receive mock data from the cows), the first `1` is
|
|
the collar ID sending the data, the second `1` is the cow's walking speed (in meters/second),
|
|
the `Coord 0 0` is the initial longitude and latitude of the cow, and `squareCow` is
|
|
the cow's actions described above.
|
|
|
|
Note that the script relies on being in the same directory as the `server` repository
|
|
containing our database model.
|