如何在"where"子句中赋予表达式泛型类型?

Mat*_*ick 7 generics haskell types where-clause type-declaration

(请原谅可怕的人为例子)

我想要做的是在where子句中指定类型:

somemap :: (a -> b) -> [a] -> [b]
somemap f xs = ys
  where
    some = take 5 xs :: [a]
    ys = map f some :: [b]
Run Code Online (Sandbox Code Playgroud)

但这会导致错误:

*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.
Run Code Online (Sandbox Code Playgroud)

而如果我指定的具体类型,替换IntaBoolb,没问题:

somemap :: (Int -> Bool) -> [Int] -> [Bool]
somemap f xs = ys
  where
    some = take 5 xs :: [Int]
    ys = map f some :: [Bool]
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:如何在where子句中指定泛型类型和类型约束?

ehi*_*ird 15

内部where条款,类型变量ab类型的变量; 类型变量没有作用域,因此每个类型的签名都有一个新的类型,就像它们是在顶层定义的一样.

如果打开ScopedTypeVariables扩展名(放在{-# LANGUAGE ScopedTypeVariables #-}文件的顶部),并将somemap类型声明更改为:

somemap :: forall a b. (a -> b) -> [a] -> [b]
Run Code Online (Sandbox Code Playgroud)

那么where你指定的子句定义将正常工作.我认为forall只有向后兼容性才需要s,因此在where多态值的子句中重用类型变量的代码不会中断.

如果你不想使用扩展,那么另一种方法是定义丑陋的辅助函数来统一类型,比如asTypeOf.