2016-12-15 9 views
3

Haskellでfor関数を騙して定義しました。Haskell:上位レベル関数の変数を参照する "where"関数の型を宣言する

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関数から変数とその変数のいずれかを比較しているという事実に関係していることを推測している - ともから変数にその変数の1を加えますfor機能。それらは同じタイプでなければなりません。それを言う方法はありますか?あるいは、for'の関数の型を宣言する別の方法がありますか?

ありがとうございました。

P.S.私はfor'関数をトップレベル関数として宣言して関連する変数を渡すことができますが、この構造体を使用して有効な宣言を書く方法があるのだろうかと思います。

P.P.S本質的に同じ質問がhereと尋ねられましたが、答えはネストされた関数の宣言を取り除くことでした。どのように動作するものを書くか?

+1

剛性型変数の不一致に対する答えは、この問題を解決しました。 Thanks – RussAbbott

答えて

1

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) 
+0

'for''に' Ord i'と 'Num i'を書き直す必要はありません。 –

+0

うまくいけば、 'for''のタプルの不必要な構築と分解は、最適化されるでしょう。しかし、それは単調であり、コードの読者はそれにつきものになり、それ自身に尋ねます:なぜここでタプルを渡す必要があるのですか? – Ingo

関連する問題