我正在编写一个在堪萨斯熔岩中将一点转换为bool的函数。 我可以用两种方式做到这一点,但它们都不起作用。
该功能必须执行以下操作:
第一种方法:
bitToBool :: Signal i Bool -> Bool
bitToBool x
| x==low = False
| otherwise = True
在这种方法中,我得到了错误"异常:未定义:信号上的Eq"
第二种方法:
bitToBool :: Signal i Bool -> Bool
bitToBool low = False
bitToBool high = True
即使输入为高,此方法也始终返回False。 这应该有效,因为在另一段代码中,我做了相反的操作,这是有效的。
我在这里做错了什么?
感谢您的帮助
大安
答案 0 :(得分:4)
在这种方法中,我得到了错误"异常:未定义:信号上的Eq"
那是因为Eq
的{{1}}实例是这样的:
Signal c a
您无法比较任何两个信号。
我在这里做错了什么?
Utils
不是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"
或low
,而是模式匹配。由于第一个模式始终匹配,因此您始终返回high
。
免责声明:我从未使用堪萨斯 - 熔岩,我不知道硬件编程,而且我几乎是Haskell的初学者。既然我已经失去了所有的信誉,那就让我们开始一段时间来获得False
!
为了从Bool
中获取内容,我们需要知道what a Signal
is:
Signal
太棒了,我们实际上可以在data Signal (c :: *) a = Signal (S.Stream (X a)) (D a)
上进行模式匹配:
Signal
现在我们可以用bitToBool (Signal _ d) = ...
做些什么?在我们的案例中,d
的类型为d
。让我们看一下low
, high
的定义,以及助手pureS
来获得灵感:
D Bool
请注意Rep
class,稍后会变得很重要。 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
的{{3}}包装,D
is a newtype
是后者的构造函数之一。因此,我们实际上可以对Driver E
以外的事物进行模式匹配,目前正在进行:
toRep
Lit
有双toRep
。 fromRep
有一些双pureX
,在这种情况下会导致bitToBool (Signal _ d) = case unD d of
Lit r -> ...
_ -> False
或Just Bool
。我们可以使用Nothing
中的fromMaybe
来完成堪萨斯州熔岩代码的小旅程:
Data.Maybe
不幸的是,我无法在我的系统上安装堪萨斯 - 熔岩,因此无法测试此解决方案,但除非我错过了所有内容,否则至少应该进行类型检查。
现在我们已经看到可能可以将bitToBool (Signal _ d) =
case unD d of
Lit r -> fromMaybe False . unX . fromRep $ r
_ -> False
转换回Signal i Bool
,这是不明智的。它可能会键入检查,但Bool
也是如此。
最后,您要从其unsafePerformIO
上下文中删除布尔值。但是,由于这最终是硬件/ VHDL,这并不是真的很明智:
你无法以任何合理的方式将信号转变为布尔。信号在" time"之间变化,因此将它与静态布尔值进行比较毫无意义。这就是为什么比特没有比较功能的原因。所以,你在这里走错了路。 -
unX
事实上,从我的角度来看,Signal
的{{1}}和Eq
个实例不应该存在。此外,一些构造函数根本不应该导出,如duplode暗示:
augustuss在问题评论中提出了一个重要问题:即使构造函数被导出,你是否应该访问信号的表示? augustss
然而,这最终取决于你的动机,因为两个原始问题都得到了回答。不幸的是,我无法回答新提出的问题"这是否有意义",这取决于在该领域拥有更多专业知识的其他人。