2016-09-11 8 views
12

Szukałem w pewnym kodzie źródłowym Haskell i natknąłem się na meczu wzór z !_, kod jest tutaj: http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.List.html#unsafeTakeKiedy jest użyteczne użycie "ścisłej wieloznacznej" w Haskell i co ona robi?

take n xs | 0 < n  = unsafeTake n xs 
      | otherwise = [] 

-- A version of take that takes the whole list if it's given an argument less 
-- than 1. 
{-# NOINLINE [1] unsafeTake #-} 
unsafeTake :: Int -> [a] -> [a] 
unsafeTake !_ []  = [] 
unsafeTake 1 (x: _) = [x] 
unsafeTake m (x:xs) = x : unsafeTake (m - 1) xs 

I naprawdę nie rozumiem, w jaki sposób „surowe wieloznaczny” działa i dlaczego jest przydatna ta funkcja (lub jakakolwiek inna funkcja).

Odpowiedz

12

Chodzi o to, że unsafeTake (i take dla tej sprawy), gdy poproszony o powrót pierwszych m elementów pustej listy, należy zwrócić pustą listę, bez względu na to, jaka jest wartość m jest. Ale co, jeśli m jest wyrażeniem, które zgłasza wyjątek? Na przykład, byłoby dziwne, aby unsafeTake undefined [] powrócił []. Musimy więc upewnić się, że m jest wartością całkowitą, nawet jeśli nie obchodzi nas, jaka jest jej dokładna wartość (oczywiście dla pustej listy). To sprawia, że ​​unsafeTake zachowuje się tak samo, jeśli chodzi o pierwszy argument, nie ma znaczenia, czy drugi argument (lista) jest pusty, czy nie.

+1

Przypuszczam, że warto wspomnieć, że jeśli użyje się funkcji 'take' z' undefined' jako argumentu 'n', to jest mało prawdopodobne, aby złapać błąd w funkcji' unsafeTake', ponieważ 'n' jest porównywany z zerem wcześniej, tzn. być wcześniej ocenione. Ale ponieważ funkcja 'take' ma być w jak największym stopniu zorientowana (jak mówi komentarz), to ta kontrola może zniknąć po pewnych optymalizacjach. Dlatego potrzebujemy '! _' również w' unsafeTake'. – Shersh

Powiązane problemy