(请原谅这个可怕的人为的例子)
我想要做的是在 where 子句中指定类型:
somemap :: (a -> b) -> [a] -> [b]
somemap f xs = ys
where
some = take 5 xs :: [a]
ys = map f some :: [b]
但这会导致错误:
*Main> :load file.hs
[1 of 1] Compiling Main ( file.hs, interpreted )
fil.hs:15:18:
Couldn't match expected type `a1' against inferred type `a'
`a1' is a rigid type variable bound by
an expression type signature at file.hs:15:25
`a' is a rigid type variable bound by
the type signature for `somemap' at file.hs:12:12
Expected type: [a1]
Inferred type: [a]
In the second argument of `take', namely `xs'
In the expression: take 5 xs :: [a]
file.hs:16:13:
Couldn't match expected type `b1' against inferred type `b'
`b1' is a rigid type variable bound by
an expression type signature at file.hs:16:24
`b' is a rigid type variable bound by
the type signature for `somemap' at file.hs:12:17
In the first argument of `map', namely `f'
In the expression: map f some :: [b]
In the definition of `ys': ys = map f some :: [b]
Failed, modules loaded: none.
而如果我只是指定具体类型,则替换为
Int
对于 a
和 Bool
对于 b
, 没问题:somemap :: (Int -> Bool) -> [Int] -> [Bool]
somemap f xs = ys
where
some = take 5 xs :: [Int]
ys = map f some :: [Bool]
所以我的问题是:如何在 where 子句中指定泛型类型和类型约束?
最佳答案
里面where
子句,类型变量 a
和 b
是新的类型变量;类型变量没有作用域,所以每个类型签名都有新的供应,就像它们是在顶层定义的一样。
如果您打开 ScopedTypeVariables
扩展名(将 {-# LANGUAGE ScopedTypeVariables #-}
放在文件顶部),然后更改 somemap
的类型声明为:
somemap :: forall a b. (a -> b) -> [a] -> [b]
然后
where
您指定的子句定义将正常工作。我认为 forall
s 仅用于向后兼容,因此在 where
中重用类型变量的代码多态值的子句不会中断。如果您不想使用扩展,另一种方法是定义丑陋的辅助函数来统一类型,例如
asTypeOf
.
关于generics - 如何在 "where"子句中给出表达式泛型类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10434333/