나는 그것을 반 진실이라고 생각합니다. Haskell은 추상화하는 놀라운 능력을 가지고 있으며, 여기에는 명령형 아이디어에 대한 추상화가 포함됩니다. 예를 들어, Haskell에는 명령형 while 루프가 내장되어 있지 않지만 작성 만하면됩니다.
while :: (Monad m) => m Bool -> m () -> m ()
while cond action = do
c <- cond
if c
then action >> while cond action
else return ()
이 수준의 추상화는 많은 명령형 언어에서 어렵습니다. 이것은 클로저가있는 명령형 언어로 수행 할 수 있습니다. 예. Python 및 C #.
그러나 Haskell 은 Monad 클래스를 사용하여 허용되는 부작용 을 특성화 하는 (매우 고유 한) 능력도 있습니다. 예를 들어, 함수가있는 경우 :
foo :: (MonadWriter [String] m) => m Int
이것은 "명령 적"함수일 수 있지만 두 가지만 수행 할 수 있다는 것을 알고 있습니다.
콘솔에 인쇄하거나 네트워크 연결 등을 설정할 수 없습니다. 추상화 기능과 결합하여 "스트림을 생성하는 모든 계산"등에 작용하는 함수를 작성할 수 있습니다.
매우 훌륭한 명령형 언어로 만드는 것은 Haskell의 추상화 능력에 관한 것입니다.
그러나 거짓 절반은 구문입니다. 나는 Haskell을 명령형 스타일로 사용하는 것이 매우 장황하고 어색하다고 생각합니다. 다음은 while
연결 목록의 마지막 요소를 찾는 위의 루프를 사용한 명령형 계산의 예입니다 .
lastElt :: [a] -> IO a
lastElt [] = fail "Empty list!!"
lastElt xs = do
lst <- newIORef xs
ret <- newIORef (head xs)
while (not . null <$> readIORef lst) $ do
(x:xs) <- readIORef lst
writeIORef lst xs
writeIORef ret x
readIORef ret
모든 IORef 가비지, 이중 읽기, 읽기 결과 바인딩, fmapping ( <$>
) 인라인 계산 결과 작업 ... 모두보기가 매우 복잡합니다. 기능 적인 관점에서 보면 상당히 의미가 있지만 명령형 언어는 이러한 세부 사항의 대부분을 사용하기 쉽게 만들기 위해 깔개 아래로 훑어 보는 경향이 있습니다.
물론 우리가 다른 while
스타일의 결합자를 사용한다면 더 깨끗할 것입니다. 그러나 그 철학을 충분히 이해한다면 (자신을 명확하게 표현하기 위해 풍부한 조합자를 사용하여), 다시 함수형 프로그래밍에 도달하게됩니다. 명령형 하스켈은 잘 설계된 명령형 언어, 예를 들어 파이썬처럼 "흐르지"않습니다.
결론적으로, 통사론 적 변형을 통해 Haskell은 최고의 명령형 언어 일 수 있습니다. 그러나 페이스 리프트의 특성상 내부적으로 아름답고 실제적인 것을 외부 적으로 아름답고 가짜로 대체하는 것입니다.
편집 : lastElt
이 파이썬 음역과 대조 :
def last_elt(xs):
assert xs, "Empty list!!"
lst = xs
ret = xs.head
while lst:
ret = lst.head
lst = lst.tail
return ret
라인 수는 같지만 각 라인에는 노이즈가 상당히 적습니다.
2 편집
그만한 가치 는 Haskell 의 순수한 대체품 이 어떻게 생겼는지입니다.
lastElt = return . last
그게 다야. 또는 다음을 사용하는 것을 금지하는 경우 Prelude.last
:
lastElt [] = fail "Unsafe lastElt called on empty list"
lastElt [x] = return x
lastElt (_:xs) = lastElt xs
또는 Foldable
데이터 구조 에서 작동하고 실제로 오류를 처리 할 필요 가 없다는 것을 인식하려면 다음을 수행하십시오 IO
.
import Data.Foldable (Foldable, foldMap)
import Data.Monoid (Monoid(..), Last(..))
lastElt :: (Foldable t) => t a -> Maybe a
lastElt = getLast . foldMap (Last . Just)
와 함께 Map
, 예 :
λ➔ let example = fromList [(10, "spam"), (50, "eggs"), (20, "ham")] :: Map Int String
λ➔ lastElt example
Just "eggs"
(.)
연산자는 함수 조성물 .