With the following "toy model" of Clash:
{-# LANGUAGE RankNTypes, KindSignatures, DataKinds, FlexibleContexts #-}
-- Simplified model of platform definitions
data Domain = DomSys | Dom25
data Signal (dom :: Domain)
data Clock (dom :: Domain)
class HiddenClock (dom :: Domain)
withClock :: Clock dom -> (HiddenClock dom => r) -> r
withClock _ _ = undefined
I would like to use withClock to close over the HiddenClock constraint inside a local where block. Suppose I have the following two toplevel definitions:
-- Simplified model of external standalone definitions
mainBoard :: (HiddenClock dom) => Signal dom -> Signal dom -> Signal dom -> (Signal dom, Signal dom)
mainBoard = undefined
peripherals :: (HiddenClock dom) => Signal dom -> Signal dom
peripherals = undefined
video
:: Clock domVid
-> Clock domSys
-> Signal domSys
-> Signal domSys
-> (Signal domVid, Signal domSys, Signal domSys)
video = undefined
then, I would like to write something like the following:
topEntity :: Clock Dom25 -> Clock DomSys -> Signal DomSys -> Signal Dom25
topEntity clkVid clkSys input = vga
where
(vga, vidRead, line) = video clkVid clkSys vidAddr vidWrite
(vidAddr, vidWrite) = withClock clkSys board
board = mainBoard vidRead line p
where
p = peripherals input
Unfortunately, GHC (at least as of 8.10.7) is unable to infer the correct type for board, which causes withClock clkSys board to not really close over the HiddenClock DomSys constriant:
• No instance for (HiddenClock 'DomSys)
arising from a use of ‘mainBoard’
• In the expression: mainBoard vidRead line p
In an equation for ‘board’:
board
= mainBoard vidRead line p
where
p = peripherals input
In an equation for ‘topEntity’:
topEntity clkVid clkSys input
= vga
where
(vga, vidRead, line) = video clkVid clkSys vidAddr vidWrite
(vidAddr, vidWrite) = withClock clkSys board
board
= mainBoard vidRead line p
where
p = peripherals input
|
38 | board = mainBoard vidRead line p
| ^^^^^^^^^^^^^^^^^^^^^^^^
• No instance for (HiddenClock 'DomSys)
arising from a use of ‘peripherals’
• In the expression: peripherals input
In an equation for ‘p’: p = peripherals input
In an equation for ‘board’:
board
= mainBoard vidRead line p
where
p = peripherals input
|
40 | p = peripherals input
| ^^^^^^^^^^^^^^^^^
This can be worked around by adding a type signature to board:
board :: (HiddenClock DomSys) => (Signal DomSys, Signal DomSys)
My question is: is it possible to change this code slightly, or fiddle with the exact type of withClock etc., to make this definition of topEntity typecheck without a type signature on the binding of board?