Происходит проверка: невозможно построить бесконечный тип - PullRequest
0 голосов
/ 29 сентября 2018

Задача, которую я хочу выполнить, описана ниже:

pipe [f1,...,fn] x должен вернуть f1(f2(...(fn x)))

Вот мой код:

pipe :: [(a -> a)] -> (a -> a)
pipe fs   = foldl' f base fs
  where
    f a x = a (x)
    base  = (\x -> x)

Я думаю, что это имеет смысл, поскольку он перебирает список функций, однако компилятор говорит мне:

tutorial.hs:45:20: error:
    • Occurs check: cannot construct the infinite type: a ~ a -> a
      Expected type: (a -> a) -> (a -> a) -> a -> a
      Actual type: ((a -> a) -> a -> a) -> (a -> a) -> a -> a
    • In the first argument of ‘foldl'’, namely ‘f’
      In the expression: foldl' f base fs
      In an equation for ‘pipe’:
         pipe fs
            = foldl' f base fs
            where
                f a x = a (x)
                base = (\ x -> x)
    • Relevant bindings include
        fs :: [a -> a] (bound at tutorial.hs:45:6)
        pipe :: [a -> a] -> a -> a (bound at tutorial.hs:45:1)
   |
45 | pipe fs   = foldl' f base fs
   |                    ^
Failed, no modules loaded.

Я новичок в Haskell, и спасибо за вашу помощь заранее:)

Ответы [ 2 ]

0 голосов
/ 29 сентября 2018

Я объясню, почему ваш код не работает.Давайте вычислим pipe [g,h] x.Мы ожидаем, что это будет g(h x).

. Я буду игнорировать типы и просто вычислять в соответствии с определениями:

pipe [g,h] x
= foldl' f base [g,h] x
= foldl' f (f base g) [h] x
= foldl' f (f (f base g) h) [] x
= f (f base g) h x
= (f base g) h x
= base g h x
= g h x

Итак, в последней строке мы видим, что g вызывается с двумя аргументами h и x, в то время как мы ожидали получить g (h x).

Ошибка в том, что f использует приложение f a x = a x вместо композиции f a x = a . x.Используя последнее, мы получим

... 
= ((base . g) . h) x
= base (g (h x))
= g (h x)
0 голосов
/ 29 сентября 2018

Вы можете сделать

pipe :: [a -> a] -> (a -> a)
pipe = foldr (flip (.)) id

Существует разница между foldr и foldl.

Ваша base функция эквивалентна id.

В вашей версии определение f неверно.Он должен принимать две функции и возвращать новую функцию.

Вы можете написать ее как

pipe :: [(a -> a)] -> (a -> a)
pipe fs   = foldl f id fs
  where
    f g h = g . h
    base  = (\x -> x)

или

pipe :: [(a -> a)] -> (a -> a)
pipe fs   = foldl f id fs
  where
    f g h a = h (g a)
    base  = (\x -> x)

Если все функции являются коммутативными, используйте foldr или foldl не имеет значения, в противном случае вам нужно правильно выбрать foldr или foldl.

...