컴파일러가 sum 유형 모두가 { name :: String }
을 인수로 갖고 있다고 추론 할 수없는 이유는 정확히 모르겠습니다. 나는 컴파일러가 지금 당장 그렇게 할 수 있다고 생각하지 않으며, 심지어 가능하다고 확신하지 못한다.
그렇다고해서 사용하는 유형을 내성적으로 검사 할 수있는 방법이 있으며 함수를 정의하여 Person
유형에서 작동 할 수 있습니다. 이것은 언어의 고급 영역을 탐구하고 있으며 이것은 또한 새로운 영역입니다. 이것은 아마도 여러분의 질문을 넘어서는 길일 것입니다. 그러나 다른 사람들에게 도움이 될 수 있으며, 가능한 것이 무엇인지 아는 것이 좋습니다.
먼저 "이름이있는 유형"에 대한 typecass를 정의 해 보겠습니다.
class DoesHaveName a where
getName :: a -> String
이제 Person
유형의 구조를 검사해야합니다. 이를 위해 purescript-generics-rep 패키지를 사용할 수 있습니다. 먼저 컴파일러에게 데이터 유형을 검사하여 범용 목적의 표현을 작성하라고 지시합니다. Person
유형에 대해 Generic
의 인스턴스를 만듭니다.
import Data.Generic.Rep (class Generic)
derive instance genericPerson :: Generic Person _
우리는 Data.Generic.Rep의 생성자를 보면 유형을 대표하는 모든 다른 방법을 볼 수 있습니다, 우리는 from를 사용하여 해당 구조에 Person
을 변환 할 수 있습니다.
import Data.Generic.Rep (class Generic, from)
personToString :: Person -> String
personToString a = getName (from a)
그래서 지금 우리는 { name :: String }
을 받아 하나 인수 생성자에 대한 DoesHaveName
의 인스턴스를 만들어야합니다.
import Data.Generic.Rep (class Generic, to, from, Sum(..), Rec(..), NoConstructors, Constructor(..), Field(..))
import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
instance doesHaveNameConstructor
:: (IsSymbol t0, IsSymbol t1)
=> DoesHaveName (Constructor t0 (Rec (Field t1 String))) where
getName (Constructor (Rec (Field c))) =
case (reflectSymbol (SProxy :: SProxy t1)) of
"name" -> c
_ -> "NoName"
씹을 것이 많습니다. 내가 할 수있는 한 최선을 다해 노력할 것이다. t0
및 t1
은 기호입니다. 따라서이 기호는 사용자가 작성한 문자 코드의 일부입니다. 이 경우 t0
은 Sum 유형 생성자 (Amy 또는 George)의 이름입니다. t1
은 레코드 레이블입니다 (예제에서 "name"이됩니다). 따라서 우리는 reflectSymbol
을 사용하여 심볼을 우리가 일치시킬 수있는 문자열로 변환합니다. 레이블이 "이름"이면 필드에 값을 반환하고 그렇지 않으면 "NoName"을 반환합니다.
마지막으로해야 할 일은 Sum 유형 구조에 대해 DoesHaveName
인스턴스를 생성하는 것입니다. Sum 유형은 생성자를 포함하므로이 인스턴스는 기본적으로 외부 구조를 처리하고 위에서 정의한 인스턴스에 위임합니다.
instance doesHaveNameSum
:: (DoesHaveName a, DoesHaveName b)
=> DoesHaveName (Sum a b) where
getName (Inl a) = getName a
getName (Inr b) = getName b
이제 우리는 사람의 이름을 모든 종류의 로그인 할 수 있습니다 ...
data Person
= Amy { name :: String }
| George { name :: String }
| Jim { name :: String }
-- Logs "amy"
log $ personToString (Amy { name: "amy" }
-- Logs "george"
log $ personToString (George { name: "george" }
-- Logs "jim"
log $ personToString (Jim { name: "jim" }
데모 : http://try.purescript.org/?gist=2fc95ad13963e96dd2a49b41f5703e21 생성자가 무시 될 수있는 경우
왜 변수에 일치시키지 않고 이름에'name'을 사용합니까? 'personToString p = name p' – arrowd
분명히 할 수 있었지만,이 인위적인 예제를 사용하여 무슨 일이 일어나고 있는지 이해하고있었습니다 ... –