I'm writing a function which converts a bit to a bool in Kansas Lava. I can do this in two ways but neither of them works.
The function must do the following:
First method:
bitToBool :: Signal i Bool -> Bool
bitToBool x
| x==low = False
| otherwise = True
In this method I get the error "Exception: undefined: Eq over a signal"
Second method:
bitToBool :: Signal i Bool -> Bool
bitToBool low = False
bitToBool high = True
This method always returns False even if the input is high. This should work because in an another piece of code I do the reverse of this, which works.
What am I doing wrong here?
Thanks for the help
Daan
In this method I get the error "Exception: undefined: Eq over a signal"
That's because the Eq
instance for Signal c a
is as such:
instance (Rep a, Eq a) => Eq (Signal c a) where
-- Silly question; never True; can be False.
(Signal _ _) == (Signal _ _) = error "undefined: Eq over a Signal"
You can't compare any two signals.
What am I doing wrong here?
That's not low
or high
from Utils
, but instead pattern matching. And since the first pattern always matches, you always return False
.
Disclaimer: I've never used Kansas-Lava, I have no idea about hardware programming, and I'm pretty much a Haskell beginner. Now that I've lost all my credibility, lets start on a journey to get that Bool
!
In order to get something out of a Signal
, we need to know what a Signal
is:
data Signal (c :: *) a = Signal (S.Stream (X a)) (D a)
Great, we can actually pattern match on Signal
:
bitToBool (Signal _ d) = ...
Now what can we do with d
? d
has type D Bool
in our case. Lets have a look at the definition of low
, high
, and also the helper pureS
to get some inspiration:
pureS :: (Rep a) => a -> Signal i a
pureS a = Signal (pure (pureX a)) (D $ Lit $ toRep $ pureX a)
high :: (sig ~ Signal i) => sig Bool
high = pureS True
low :: (sig ~ Signal i) => sig Bool
low = pureS False
Note the Rep
class, it gets important later. D
is a newtype
wrapper for Driver E
, Lit
is one of the constructors for the latter. So we can actually pattern match for the things up to toRep
and are currently at this point:
bitToBool (Signal _ d) = case unD d of
Lit r -> ...
_ -> False
toRep
has a dual fromRep
. And pureX
has a somewhat dual unX
, which in this case leads to Just Bool
or Nothing
. We can use fromMaybe
from Data.Maybe
to finish our little journey through the Kansas Lava code:
bitToBool (Signal _ d) =
case unD d of
Lit r -> fromMaybe False . unX . fromRep $ r
_ -> False
Unfortunately, I couldn't install kansas-lava on my system and therefore couldn't test this solution, but unless I've missed something everything should at least type check.
Now that we've seen that it might be possible to transform a Signal i Bool
back to a Bool
, it isn't wise. It might type check, but so does unsafePerformIO
.
In the end, you're removing a boolean value from its Signal
context. However, since this is hardware/VHDL at the end, that's not really sensible:
You can't turn a Signal into a Bool in any sensible way. Signals vary over "time", so comparing it with a static boolean makes little sense. That's why there's no comparison function for bits. So, you're on the wrong track here. –augustss
In fact, the Eq
and Ord
instances for Signal
shouldn't exist from my point of view. Also, some of the constructors shouldn't be exported at all, as duplode hints:
augustuss raises an important issue in the question comments: even if the constructors are exported, are you supposed to access the representation of a signal? –duplode
However, it ultimately depends on your motives, as both original questions have been answered. Unfortunately, I cannot answer the new risen question "Does that make sense", that's up to someone else who has more expertise in this field.