I'm relatively new to haskell so forgive me if this is really obvious.
Basically I have two Bool and based on them I want to choose the implementation of 3 different functions. In the case that both bools are equal (e.g. both True or both False) the functions should do nothing. Then there are different implementation if one or the other Bool is True.
These function involve constraints so for instance the first function has an Ord or Bounded constraint on the parameters. The second function has a Num constraint on the parameters.
The problem I am having is that I have no clue how to make the type checker oke with this construct. See below for a minimal example that complains when I pattern match on the result:
f :: (Ord a, Bounded a) => a -> a -> a
f a b = if a > b then maxBound else minBound
g :: (Ord a, Bounded a) => a -> a -> a
g a b = if a > b then minBound else maxBound
a = True
b = False
test
| a == b = (const, const, const)
| a = (f, (-), (+))
| b = (g, (+), (-))
(resF, _, _) = test
(_, resG, _) = test -- error Could not deduce (Ord b0) arising from a use of ‘test’
-- from the context: Num b
-- Same error occurs for the last value in the tuple.
Run Code Online (Sandbox Code Playgroud)
I'm not sure how the function with the most constraints resF is completely fine with being assigned to a variable but resG complains...
Any help is appreciated!
TL; DR版本:因为GHC将默认Num b2和Num b3,但不会(Ord b1, Bounded b1)。
这是defaulting类型的问题。的类型test推断为(Ord b1, Bounded b1, Num b2, Num b3) => (b1 -> b1 -> b1, b2 -> b2 -> b2, b3 -> b3 -> b3)。这种类型的手段,如果你提供了一个Ord和Bounded某些类型的实例b1,以及Num对于某些类型的实例b2和b3,你会得到函数的元组。当您将元组拆开并只保留其中一个时,其他约束不仅会消失,因此您基本上有了resF :: (Ord b1, Bounded b1, Num b2, Num b3) => b1 -> b1 -> b1and resG :: (Ord b1, Bounded b1, Num b2, Num b3) => b2 -> b2 -> b2。
现在,在resF,b2和b3含糊不清的类型,因为他们是在左侧的使用=>,但不正确的。根据类型默认规则,这些将默认为Integer,因此最终您将拥有一个resF真正的类型(Ord b1, Bounded b1) => b1 -> b1 -> b1并且一切正常。
resG是不同的。在这里面,b1并且b3是模糊的类型。b3默认情况与Integer一样resF。但是,GHC没有b1满足约束条件的默认值(Ord b1, Bounded b1),因此会给您带来这种效果的错误(肯定可以更加清楚)。
要解决此问题,您需要告诉GHC什么类型b1。由于您保留的元组片段没有使用b1,因此您可以选择任何所需的内容,这无关紧要。这是一种实现方式(在此示例中,我选择了Int):
(_, resG, _) = test :: (Num b2, Num b3) => (Int -> Int -> Int, b2 -> b2 -> b2, b3 -> b3 -> b3)
Run Code Online (Sandbox Code Playgroud)