Elmのmoduleのimportが知りたくてーー。

Elmのmoduleのimportが知りたくて――。

北海道札幌市内の住宅で、Elmのmoduleのimport処理を、とりあえず雑にqualified importしたとして、札幌中央警察署は22日、北海道札幌市、無職すがわに容疑者(24)をmodule適当にimportした容疑で逮捕したと発表した。

「Html.Attributes.maxが使いたかった」と容疑を認めているという。
f:id:nekorollykk:20200822194559p:plain

今回のお話

nekoroll.hatenablog.com

モジュール内の名前がかぶった場合
Basics.maxとHtml.Attributes.max

progressmax属性が怒られてしまった

import Html exposing (..)
import Html.Attributes exposing (max, value)

, progress 
      [ Html.Attributes.max "100"
      , Html.Attributes.value "80"
      ]
      []

これをどうするか

教えてもらった


id,nameとの衝突を考えてないポンコツ

ABAB↑↓BAさんが自分の発言を拾ってくれて本当にありがたいです
モチベがお餅モチモチ雪見だいふくです

参考ページを読み解く

elm-lang.org

qualified import

module名.関数名 で呼び出す事ができる

import Html.Attributes

完全修飾名指定で使える

import Html.Attributes

, progress 
      [ Html.Attributes.max "100"
      , Html.Attributes.value "80"
      ]
      []

import Html.Attributes as Attribute

別名を指定して関数を使える

import Html.Attributes as Attribute

, progress 
      [ Attribute.max "100"
      , Attribute.value "80"
      ]
      []

open import

関数名で直接呼び出すことができる(module名が不要)

import Html.Attributes exposing (..)

module内の関数を全部まとめて使える
※以下ケースだとmaxBasics.maxと衝突するのでNG

import Html.Attributes exposing (..)

, progress 
      [ Html.Attributes.max "100"
      , Html.Attributes.value "80"
      ]
      []

import Html.Attributes exposing (max, value)

指定したmodule内の関数が使える ※以下ケースだとmaxBasics.maxと衝突するのでNG

import Html.Attributes exposing (max, value)

, progress 
      [ Html.Attributes.max "100"
      , Html.Attributes.value "80"
      ]
      []

asとexposing両方

import Html.Attributes as Attribute exposing (..)

import Html.Attributes as Attribute exposing (..)

, progress 
      [ Attributes.max "100"
      , value "80"
      ]
      []

感想

  • import Html.Attributes
    文字数が少ないぐらいしかいいところが思いつかない
    毎回Html.Attributesって書きたくない
  • import Html.Attributes as Attribute 明示的でCOOL。結構好き
    後述するexposingとの合わせ技がかなり好み
  • import Html.Attributes exposing (..)
    雑だけど楽
    衝突しやすい関数名とか地獄見そう(mapとか)
  • import Html.Attributes exposing (max, value)
    サンプルでも使われてるし、何importしてるのか明示的で好き
    ただ衝突が悲しい
  • import Html.Attributes as Attribute exposing (..)
    雑に楽したい俺の心を満たす素敵なヤツ
    衝突しないやつは(..)で問題なく使える
    衝突したらAttributes.で使える

おまけ

compiler/imports.md at 9d97114702bf6846cab622a2203f60c2d4ebedf2 · elm/compiler · GitHub
elm/compilerにインポートのヒントがあったので読んでみた

雑意訳

英検三級レベルなので温かい目でみてください

import

import モジュール名でモジュールをインポートして使用できます
Htmlモジュールのdiv関数を使う場合は以下の記法です

import Html

main =
  Html.div [] []

HtmlモジュールのHtml型を使う場合は以下の記法です

import Html

main : Html.Html msg
main =
  Html.div [] []

※注意
モジュールは他のモジュールを含まないので
import HtmlだけではHtml.Attributesを使用することはできません
たまたまHtmlが重なっているだけの別のモジュールです
使用したい場合はimport Html.Attribtuesでインポートする必要があります

as

qualified importするのがベストプラクティスですが、名前が長くなることがあります
その場合はasで別名をつけることができます

import Html
import Html.Attributes as A

main =
  Html.div [ A.style "color" "red" ] [ Html.text "Hello!" ]

これでHtml.Attributesモジュールの関数や型をAで呼び出すことができます

exposing

下書き等でサクッと使いたい場合exposingを使用できます

import Html exposing (..)
import Html.Attributes exposing (style)

main : Html msg
main =
  div [ style "color" "red" ] [ text "Hello!" ]

exposing (..)はモジュール名無しで関数や型を呼び出すことができます
上の例では

  • HtmlモジュールのHtml
  • Htmlモジュールのdiv,text関数
  • Html.Attributesstyle関数

がモジュール名無しで呼び出されています
※注意
一見スッキリしているように見えますが、たくさんのモジュールをexposing (..)した場合、
きっとすぐにコード内の関数がどこから呼ばれているのか混乱するでしょう
そしてimportを整理し始めるはずです
ポイントは(..)を使用しないことです!

as and exposing

asexposingを使用して、バランス良くインポートできます

import Html exposing (Html, div, text)
import Html.Attributes as A exposing (style)

main : Html msg
main =
  div [ A.class "greeting", style "color" "red" ] [ text "Hello!" ]
  • Html.Attributes.style
    exposing (style)でインポートしているのでstyle(モジュール名なし)
  • Html.Attributes.class
    Html.Attributes as AでインポートしているのでA.class(asで指定したモジュール名)

となっています

デフォルトでインポートされるモジュールについて

一般的によく使用されるモジュールの中には、
Elmコンパイラが自動的に全てのファイルにインポートを追加するものがあります
デフォルトでインポートされるモジュールは以下のようなものがあります

import Basics exposing (..)
import List exposing (List, (::))
import Maybe exposing (Maybe(..))
import Result exposing (Result(..))
import String
import Tuple

import Debug

import Platform exposing (Program)
import Platform.Cmd as Cmd exposing (Cmd)
import Platform.Sub as Sub exposing (Sub)

上記のインポートは、モジュールの先頭に常にあると考えられられます
(すがわに:暗黙的なインポートが常に存在する感じ)

Maybe型はElmのエラー処理を行うための基本的なものであり、基本的な言語の一部であるという主張もあります
また、Elmを使い慣れてくると、「毎回Maybeモジュールをインポートするのが面倒だ」という意見もあります
いずれにしても、デフォルトのインポートはそういった意味では理想的ではないということはわかっているので、デフォルトのインポートは最小限に留めています
※注意
とても大きな(何百もの関数を持つ)モジュールをインポートしても、
Elmコンパイラは自動的にデッドコードを検出し、モジュール内の未使用の関数はアセットに含めないため、アセットのサイズを心配する必要はありません

まとめ&感想

  • 基本的にはqualified importが良さそう
  • exposing (..)は学習段階ではいいけど、実際にアプリケーションを実装する場合は避けるべき
    Html.AttributesとかはHtml.Attributes as Aとか短くするのが良さそう
    今のうちに癖つけておこうかな
  • Basics.maxHtml.Attributes.maxが被る理由がわかった
    Basicsなんてインポートしてないな…暗黙的なやつかな…」とふわふわしてた部分がハッキリした
  • 事情とかベストプラクティス書いてくれるのめちゃくちゃ親切
    開発元が決めてくれたらそれに沿って進められるし、ありがたい

追記

guide.elm-lang.jp

exposingを使うのはほんのちょっとだけにしておくのをお勧めします。
まったく使わないか、ひとつのインポートだけで使うのが理想的でしょう。
そうしないと、読むときに型や関数がどのモジュールから来ているのかを把握するのが難しくなっていくことがあります。
「待って、filterPostByはどこから来たんだっけ? 引数は何を取るんだっけ?」
exposingを追加するにつれて、コードを読んでいくのはどんどん難しくなっていきます。
私はimport Html exposing (..) をよく使いますが、それ以外ではまったく使いません。
まずは基本的なimportを使い、もし特に長いモジュール名であるときはasを使うことをお勧めします!

改めてガイド読んだら全部書いてましt(ここで日記は途切れている)