私はそれを半分の真実だと思います。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
これは「命令型」の関数になる可能性がありますが、実行できるのは2つのことだけです。
コンソールに出力したり、ネットワーク接続を確立したりすることはできません。抽象化機能と組み合わせて、「ストリームを生成する任意の計算」などに作用する関数を作成できます。
Haskellを非常に優れた命令型言語にするのは、実際には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は、Pythonなどの適切に設計された命令型言語のように「流れる」ことはありません。
結論として、構文の改良により、Haskellはおそらく最高の命令型言語かもしれません。しかし、フェイスリフトの性質上、内部的に美しく本物の何かを外部的に美しく偽物の何かに置き換えることになるでしょう。
編集:lastElt
このPythonの音訳と対比:
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"
(.)
オペレータは、関数組成物。