2016-12-15 2 views
3

Я обманывал и определял функцию for в Haskell следующим образом.Haskell: объявление типа для функции «где», которая ссылается на переменные в функции более высокого уровня

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

Ответ, заданный для несоответствия переменных жесткого типа, решил проблему. Спасибо – 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

Вам не нужно выписывать 'Ord i' и' Num i' снова в 'for''. –

+0

Надеюсь, ненужная конструкция и деконструкция кортежей в 'for'' будут оптимизированы. Тем не менее, он является унииоматическим, и читатель кода наткнется на него и спросит себя: зачем нам здесь проходить кортеж? – Ingo

Смежные вопросы