대수 데이터 유형의 용도는 무엇입니까?


16

Algebraic Data Types 에 대해 읽고 있습니다 (Richard Minerich 덕분 에이 개념에 대한 훌륭한 설명 을 발견했습니다 ). 합계 유형 및 제품 유형 등의 개념을 이해하고 있다고 생각하지만 이해하지 못하는 것은 대수 데이터 유형이 패턴 일치를 지정하는 것보다 어떻게 유용하다는 것입니다. 패턴 일치를 넘어 ADT로 할 수있는 다른 작업은 무엇입니까?


편집 : 나는 객체로 할 수없는 ADT로 개발자가 할 수있는 일을 묻지 않습니다. ADT가 허용하는 다른 작업이 있는지 묻습니다. 예를 들어 ADT를 사용하는 경우 관련된 유형에 대해 추론을 추가 할 수 있습니까? ADT가 없으면 불가능한 일종의 유형 분석을 용이하게합니까?


2
메소드 호출을 제외한 객체로 무엇을 할 수 있습니까?

1
ADT는 실제로 대수 데이터 형식이 아니라 "추상 데이터 형식"을 나타냅니다 .
Rein Henrichs

4
@Rein : 상황에 따라 참조 할 수 있습니다.
sepp2k

4
@Rein : 그것은 실제로 그렇습니다 (정직한 것이 놀랍습니다) : ADT에 대한 wikipedia 기사는 가능한 의미로 Abstract Data Type과 Algebraic Data Type을 모두 나열합니다. ADT는 Haskell 메일 링리스트 및 IRC 채널과 같은 대수 데이터 유형의 약어로 매우 일반적으로 사용됩니다.
sepp2k

1
@Rein, 나는 알고있다. "Algebraic Data Type"을 반복해서 입력하는 것에 지 쳤고 사람들이 내가 문맥에서 언급 한 것을 이해할 수있을 것이라고 생각했다.
오노 리오 카테 나치

답변:


10

대수 데이터 유형은 여러 유형의 "사물"로 구성 될 수 있다는 점에서 구별됩니다. 예를 들어 Tree는 아무것도 포함하지 않거나 (Empty), Leaf 또는 Node를 포함 할 수 있습니다.

data Tree = Empty
          | Leaf Int
          | Node Tree Tree

노드는 두 개의 트리로 구성되므로 대수 데이터 유형은 재귀적일 수 있습니다.

패턴 일치를 통해 대수 데이터 형식을 형식 안전성을 유지하는 방식 으로 해체 할 수 있습니다 . 다음과 같은 깊이 및 유사 코드 구현을 고려하십시오.

depth :: Tree -> Int
depth Empty = 0
depth (Leaf n) = 1
depth (Node l r) = 1 + max (depth l) (depth r)

다음과 비교 :

switch on (data.constructor)
  case Empty:
    return 0
  case Leaf:
    return 1
  case Node:
    let l = data.field1
    let r = data.field2
    return 1 + max (depth l) (depth r)

이것은 프로그래머가 Leaf1 전에 Empty를 비워서 field1이 빈 트리에서 액세스되지 않도록해야한다는 단점이 있습니다. 마찬가지로 Leaf 케이스는 Leaf에서 노드 2에 액세스 할 수 없도록 노드 케이스보다 먼저 선언해야합니다. 따라서 타입 안전은 언어에 의해 유지되지 않고 오히려 프로그래머에게 추가적인인지 부하를 부과합니다. 그건 그렇고, 나는 Wikipedia 페이지에서 직접 예제를 가져옵니다.

물론 오리를 입력하는 랑게 쥬는 다음과 같이 할 수 있습니다.

class Empty
  def depth
    0
  end
end

class Leaf
  def depth
    1
  end
end

class Node
  attr_accessor :field1, :field2

  def depth
    1 + [field1.depth, field2.depth].max
  end
end

따라서 대수적 데이터 유형은 OOP와 동등하지 않을 수도 있지만 소프트웨어를 구성 할 때 다른 장력을 제공합니다.


9

나는 설명이 그렇게 훌륭 하다는 것을 확신하지 못한다 .

대수 데이터 형식은 목록 및 트리와 같은 데이터 구조를 만드는 데 사용됩니다.

예를 들어 구문 분석 트리는 대수 데이터 구조로 쉽게 표현할 수 있습니다.

data BinOperator = Add
                 | Subtr
                 | Div
                 | Mult
                 | Mod
                 | Eq
                 | NotEq
                 | GreaterThan
                 | LogicAnd
                 | LogicOr
                 | BitAnd
                 | BitOr
                 | ...

data UnOperator = Negate
                | Not
                | Increment
                | Decrement
                | Complement
                | Ref
                | DeRef


data Expression = Empty
                | IntConst Int
                | FloatConst Float
                | StringConst String
                | Ident String
                | BinOp BinOperator Expression Expression
                | UnOp UnOperator Expression Bool //prefix or not
                | If Expression Expression Expression
                | While Expression Expression Bool //while vs. do while
                | Block List<Expression>
                | Call Expression List<Expression>
                | ...

실제로 C 언어를 나타내는 데 훨씬 더 많은 시간이 걸리지 않습니다.

그러나 실제로 대수 데이터 형식으로 모든 것을 할 수 있습니다. Lisp이 입증 한 바에 따르면, 한 쌍으로 모든 작업을 수행 할 수 있으며 ADT는이 접근 방식에보다 세분화 된 유형의 안전한 방법을 제공합니다.

물론, "ADT로 무엇을 할 수 있고, 개체로는 할 수 없습니까?"라고 물으면 대답은 "아무것도 없습니다"입니다. 때때로 (대부분) ADT에 대한 솔루션은 덜 장황한 반면 객체를 기반으로 한 솔루션은 더 유연하다는 것을 알 수 있습니다. ADT로 표시되는 구문 분석 트리에 넣으려면 다음을 수행하십시오.

If(Call(Ident('likes_ADTs'),[Ident('you')]),
   Call(Ident('use_ADTs'),[Ident('you')]),
   Call(Ident('use_no_ADTs'),[Ident('you')]))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.