2017-04-09 100 views
0

我是Haskell的新手,有一個任務。我必須寫一個函數返回列表的一部分

內部 - > INT - > [U] - > [U]

即給定的輸入兩個整數i和j以及列表和函數返回屬於元素在比我大,比j小的位置上。我到目前爲止想到的是:

fromTo :: Int->Int->[u]->[u] 
fromTo i j (h:t) 
    |i == 1 && j == length(h:t) 
     = (h:t) 
|i /= 1 
    fromTo (i-1) j t 
|j /= length(h:t) 
    fromTo i j init(h:t) 

但是,我得到第二個|的語法錯誤。另外我不確定我的思路在這裏是否正確。 (INIT返回列表中沒有它的最後一個元素)

編輯:更正

|i /= 1 
    fromTo (i-1) j (h:t) 

|i /= 1 
    fromTo (i-1) j t 

回答

2

固定壓痕,加括號,和失蹤=秒。這場變革編譯,並適用於序和有限的非空列表:

fromTo :: Int -> Int -> [u] -> [u] 
fromTo i j (h : t) 
    | i == 1 && j == length (h : t) = h : t 
    | i /= 1      = fromTo (i - 1) j t 
    | j /= length (h : t)   = fromTo i j (init (h : t)) 

我認爲你在尋找這樣的事情pointfree,自然索引span

take :: Int -> [a] -> [a] 
take _ []  = [] 
take 0 _  = [] 
take n (x : xs) = x : take (n - 1) xs 

drop :: Int -> [a] -> [a] 
drop _ []  = [] 
drop 0 xs  = xs 
drop n (_ : xs) = drop (n - 1) xs 

span :: Int -> Int -> [a] -> [a] 
span i j = drop i . take (j + 1) 

span 0 3 [0 .. 10] == [0,1,2,3] 

或符合規格:

between :: Int -> Int -> [a] -> [a] 
between i j = drop (i + 1) . take j 

between 0 3 [0 .. 10] == [1,2] 
+0

那麼這是一個解決方案,但分配的重點是理解遞歸和列表。 – Stelios

+0

@Stelios重新格式化的fromTo'適用於序數和有限列表; 'fromTo 1 4 [1..100] == [1,2,3,4]'。 – suchtgott

+0

是的,它確實,現在我試圖讓它爲無限列表工作,因爲@ephemient建議 – Stelios

0

你缺少|後衛條款和車身之間=。 Haskell編譯器認爲整個事情都是警惕的,並且在遇到下一個|後衛時會感到困惑,因爲它首先需要一個機構。這將編譯(雖然它仍然是越野車):

fromTo :: Int -> Int -> [u] -> [u] 
fromTo i j (h:t) 
    | i == 1 && j == length (h:t) = 
    (h:t) 
    | i /= 1 = 
    fromTo (i-1) j t 
    | j /= length (h:t) = 
    fromTo i j (init (h:t)) 

但我會說有更好的方式來編寫此函數。例如,原則上像這樣的函數應該可以在無限列表上工作,但是使用length則不可能。

+0

確實。它不適用於無限列表。我怎麼能實現這一點,但無需知道在哪裏停止與j的無限列表工作? – Stelios

+0

@Stelios @nowhere提供的解決方案可以在無限列表上工作。研究如何「放下」和「採取」工作來理解。 – ephemient

+0

是的,但正如我所說,分配的重點是理解遞歸和列表。如果我使用容易的東西1)這是不允許的,2)我實際上想要了解遞歸和列表:P – Stelios

0

下面是完整的解決方案,它使用遞歸:

fromTo :: Int -> Int -> [u] -> [u] 
fromTo i j xs = go i j xs [] 
    where go i j (x:xs) rs 
     | i < 0 || j < 0 = [] 
     | i > length (x:xs) || j > length (x:xs) = [] 
     | i /= 0      = go (i - 1) j t 
     | j /= 1   = goo i (j -1) (rs ++ [x]) 
     | otherwise = rs 

注: go是標準的Haskell成語相比,主級功能需要額外的參數遞歸函數。 第一個條款確保否定索引導致空列表。其次對於任何超過列表大小的索引都是一樣的。 列表必須是有限的。第三個「忘記」數組頭i次。第四將積累「下一個」(j - 1)頭到rs。當所有索引都「消耗」且rs包含結果時,第五個子句將被觸發。

你可以使它在無限列表上工作。放棄第二條款。如果xs在「耗盡」索引之前爲空,則返回rs。然後函數將從「i」中取「(j-1)」元素。