Haskell:声明一个“where”函数的类型,该函数引用更高级函数中的变量

时间:2016-12-15 20:18:55

标签: haskell

我无所事事并在Haskell中定义了一个for函数,如下所示。

for :: (Ord i, Num i) => (i, i, i) -> b -> (i -> b -> b) -> b
for  (init, incr, end) initState bodyFn = for' (init, initState) bodyFn 

  where
  -- for' :: (Ord i, Num i) => (i, b) -> (i -> b -> b) -> b
  for' (index, state) bodyFn | if incr > 0 then index >= end else index <= end = state
  for' (index, state) bodyFn = for' (index + incr, bodyFn index state) bodyFn 

工作正常。

> for (1, 1, 10) 0 (\i b -> i+b)
45

我想声明where函数的类型。 (正如你所看到的,它被注释掉了。)当我删除注释标记时,我收到此错误消息。

Couldn't match expected type ‘i1’ with actual type ‘i’
  ‘i’ is a rigid type variable bound by
    the type signature for:
      for :: forall i b.
             (Ord i, Num i) =>
             (i, i, i) -> b -> (i -> b -> b) -> b
    at while.hs:5:8
  ‘i1’ is a rigid type variable bound by
    the type signature for:
      for' :: forall i1 b1.
              (Ord i1, Num i1) =>
              (i1, b1) -> (i1 -> b1 -> b1) -> b1
    at while.hs:9:11
• In the second argument of ‘(>=)’, namely ‘end’
  In the expression: index >= end
  In the expression: if incr > 0 then index >= end else index <= end
• Relevant bindings include
    bodyFn :: i1 -> b1 -> b1 (bound at while.hs:10:23)
    index :: i1 (bound at while.hs:10:9)
    for' :: (i1, b1) -> (i1 -> b1 -> b1) -> b1 (bound at while.hs:10:3)
    bodyFn :: i -> b -> b (bound at while.hs:6:34)
    end :: i (bound at while.hs:6:19)
    incr :: i (bound at while.hs:6:13)

我猜这个问题与for'函数将其中一个变量与for函数中的变量进行比较这一事实有关 - 并且还将其中一个变量添加到来自for函数的变量。它们应该是同一类型。有没有办法说出来?或者是否有另一种方式来声明for'函数的类型?

感谢。

P.S。我知道我可以将for'函数声明为顶级函数并将其传递给相关变量,但我想知道是否有办法使用此结构编写有效声明。

P.P.S基本上同样的问题被问到here,但答案是摆脱嵌套函数的声明。写一个有用的方法吗?

1 个答案:

答案 0 :(得分:2)

感谢jberryman,给Mismatch of rigid type variables的答案解决了这个问题。以下代码有效。 (请注意,bodyFn也不需要传递。)

{-# LANGUAGE ScopedTypeVariables #-}

for :: forall i b. (Ord i, Num i) => (i, i, i) -> b -> (i -> b -> b) -> b
for  (init, incr, end) initState bodyFn = for' (init, initState)  

  where
  for' :: (Ord i, Num i) => (i, b) -> b
  for' (index, state) | if incr > 0 then index >= end else index <= end = state
  for' (index, state) = for' (index + incr, bodyFn index state)