Как исправить ошибку («не может создать бесконечный тип») в моем коде и как заставить мой код работать - PullRequest
0 голосов
/ 07 января 2019

В основном я пытаюсь создать функцию, в которой вам дается список и номер, и вы должны разделить список на списки того же размера, что и указанное число, а последнее разделение может иметь длину меньше, чем номер дан

separa a xs = if length xs >= a then separaM a (drop a xs) ([take a xs]) else [xs]

separaM a xs yss = if length xs >= a then separaM a (drop a xs) (yss : (take a xs)) else separaM a [] (yss : xs)
separaM a [] yss = yss

Я ожидаю, что вывод 3 "comovais" будет ["com", "ova", "is"], но в моей программе нет вывода из-за ошибки

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Обратите внимание, что выражение:

yss : (take a xs)

(take a xs) имеет тип [b], поэтому yss имеет тип b. Но когда вы передаете yss : (take a xs) в качестве аргумента функции separaM, ожидается, что yss имеет тип [b], а не b. Вот почему произошла ошибка.

На самом деле, вам не нужно yss для сохранения результата, рекурсивная функция может быть определена как:

separaM _ [] = []
separaM a xs = (if length xs >= a then (take a xs) else xs) : 
               separaM a (drop a xs)
0 голосов
/ 07 января 2019

В вашем коде есть ошибки. Тонкая настройка неправильного использования (:) заставляет его пройти проверку типов:

separa a xs 
  | length xs >= a =  go a (drop a xs) [take a xs]
  | otherwise      =  [xs]
  where
  go a xs yss 
    | length xs >= a  =  go a (drop a xs) (yss ++ [take a xs]) 
                                  -- was: (yss : (take a xs))
    | otherwise       =  go a [] (yss ++ [xs])
                         -- was: (yss : xs)
  go a [] yss = yss

но лучше изменить его на

separa :: Int -> [a] -> [[a]]
separa a xs 
  | length xs >= a =  go a (drop a xs) [take a xs]
  | otherwise      =  [xs]
  where
  go a xs yss 
    | length xs >= a  =  go a (drop a xs) ([take a xs] ++ yss) 
    | otherwise       =  reverse ([xs] ++ yss)

Работает:

> separa 3 [1..10]
[[1,2,3],[4,5,6],[7,8,9],[10]]

Это обычная идиома «построение в обратном порядке, затем обратное построение», часто встречающаяся в строгих функциональных языках. Некоторые из них допускают построение списков в естественном порядке сверху вниз по методике, известной как tail-recursion modulo cons . Haskell ленив и позволяет нам создавать его списки естественным и простым способом сверху вниз с помощью эквивалентной защищенной рекурсии :

separa :: Int -> [a] -> [[a]]
separa a xs 
  | length xs >= a =  go a (drop a xs) [take a xs]
  | otherwise      =  [xs]
  where
  go a xs yss 
    | length xs >= a  =  --     go a (drop a xs) (yss ++ [take a xs]) 
                         yss ++ go a (drop a xs)         [take a xs] 
    | otherwise       =  -- go a [] (yss ++ [xs])
                         yss ++             [xs]

Здесь есть ошибка, одна за другой; Я оставлю это для вас, чтобы исправить самостоятельно.


Но иногда бесконечному типу присуща проблема, а не результат ошибки программирования. Затем мы можем исправить это с помощью рекурсивных типов.

Всякий раз, когда мы получаем эквивалентность типа t ~ a..b..t..c.., мы можем начать с определения типа

newtype T = MkT (a..b..T..c..)

затем посмотрите, какие переменные типа свободны, и закройте их, как

newtype T a b c = MkT (a..b..(T a b c)..c..)

Пример: Ошибка бесконечного типа при определении zip только с помощью foldr; это можно исправить?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...