Write Android apps in the Frege programming language (Haskell on the JVM) — pure Frege, no Kotlin, with much less ceremony than the original thanks to Frege's new automated FFI.
froid is two things:
- A general Frege-on-Android library — thin handles over
android.view/android.widget/android.app, with the boilerplate erased by auto-FFI and the irreducible glue (the Activity, callbacks) hidden in the library. App code writes no Java and no Kotlin. - A declarative UI in the Elm Architecture, backed by FRP — built on the
View system. You write
update :: Msg -> Model -> Modelandview :: Signal Model -> Ui Msg; froid keeps the views in sync.
module app.Counter where
import froid.app.Activity
import froid.ui.App
import froid.frp.Signal
native module type Activity where {} -- the one line that makes this an Activity
data Msg = Increment
update :: Msg -> Int -> Int
update Increment n = n + 1
view :: Signal Int -> Ui Msg
view model = column
[ dynText (fmap (\n -> "Count: " ++ show n) model)
, button "Increment" Increment
]
counter :: App Int Msg
counter = App { initial = 0, update = update, view = view }
onCreate :: Activity -> IO ()
onCreate this = runApp this counterfroid needs the auto-FFI compiler from Frege master (PR #400; no release has it
yet). The script pins a known-good commit and vendors the jar to libs/.
Requirements: a JDK in the 8–17 range (17 recommended), make, curl,
jar. byacc is not needed.
JAVA_HOME=/path/to/jdk17 tools/build-frege-snapshot.sh./gradlew :geoquiz:assembleDebug
./gradlew :geoquiz:installDebug # onto a running emulator/device
# or open in Android Studio and press RuncompileFrege<Variant> (from froid-gradle-plugin) runs the Frege compiler over
each module's src/frege, generating Java that AGP compiles and dexes.
Builds and runs. :geoquiz and :counter assemble to APKs and run on an
emulator (AGP 8.13, compileSdk 36): the question renders, True/False checks the
answer with color-coded feedback, and Prev/Next navigate — all driven by the
Frege FRP.
Roadmap: more widgets (EditText, images, lists with stable keys); the deeper
FRP correctness items (subscription disposal for rotation, transactional
glitch-freedom) are noted but not needed by the current static view tree; folding
more of the original View bindings back in where useful (they remain in git
history on master).
Frege master is pinned at commit 067cad057385d36134812bde3fc1b453e5274855.
Apache License 2.0. froid is © Michael Chavinda and contributors.