Haskell에서 다형성 방식으로 여러 유형에 대한 여러 함수 정의를 작성하려면 어떻게해야합니까?

어인 다울 링

내 유형 정의가 주어지면 :

data Tile = Revealed | Covered deriving (Eq, Show)
data MinePit = Clean | Unsafe deriving (Eq, Show)
data Flag = Flagged | Unflagged deriving (Eq, Show)
type Square = (Tile, MinePit, Flag)
type Board = [[Square]]

두 가지 기능을 만들었습니다.

  1. createBoard 는 값의 튜플 또는 'Board' 의 2D 목록을 생성합니다 . 동일한 값의 차원 n * m 목록을 초기화합니다.
createBoard :: Int -> Int -> Board
createBoard 0 _ = [[]]
createBoard _ 0 = [[]]
createBoard 1 1 = [[(Covered, Clean, Unflagged)]]
createBoard n m = take n (repeat (take m (repeat (Covered, Clean, Unflagged))))

예 :

λ> createBoard 2 3
[[(Covered,Clean,Unflagged),(Covered,Clean,Unflagged),(Covered,Clean,Unflagged)],[(Covered,Clean,Unflagged),(Covered,Clean,Unflagged),(Covered,Clean,Unflagged)]]
  1. 함수 defineIndices 는 createBoard에 의해 생성 된 보드에 대한 인덱스의 순서 목록을 목적으로 정의되었습니다.
defineIndices :: Int -> Int -> [[(Int,Int)]]
defineIndices n m = [[(i,j) | j <- [1..m]] | i <- [1..n]]

다음과 같이 작동합니다.

λ> defineIndices 2 3
[[(1,1),(1,2),(1,3)],[(2,1),(2,2),(2,3)]]

여기에서 특정 Square의 값을 인덱스를 통해 조회 할 수있는 MapBoard 를 만드는 함수를 만들었 습니다.

type MapBoard = Map (Int, Int) Square

createMapBoard :: [[(Int,Int)]] -> [[Square]] -> MapBoard
createMapBoard indices squares = M.fromList $ zip (concat indices) (concat squares)

그러나 Int (s) 쌍에서 직접 MapBoard를 생성하여 이전 기능을 구현할 수있는 메서드도 작성해야한다는 것이 합리적이었습니다. 다음과 같이 보일 수 있습니다.

createMapBoard2 :: Int -> Int -> MapBoard
createMapBoard2 n m = createMapBoard indices squares where
  indices = defineIndices n m
  squares = createBoard n m

그러나 createMapBoard를 사용하여이 상황에서 다형성을 달성 할 수 있는지 여부를 조사하고 createMapBoard2를 대신 createMapBoard로 설정했습니다. 나는 이것이 Ad-Hoc Polymorphism이라고 불리는 것을 온라인 에서 발견했습니다.

class Square a where
    square :: a -> a
    
instance Square Int where
    square x = x * x

instance Square Float where
    square x = x * x 

비슷한 것을 직접 작성하려고 시도했을 때 제가 생각 해낼 수있는 최선의 방법은 다음과 같습니다.

class MyClass a b MapBoard where
  createMapBoard :: a -> b -> MapBoard

instance createMapBoard [[(Int,Int)]] -> [[Square]] -> MapBoard where
  createMapBoard indices squares = M.fromList $ zip (concat indices) (concat squares)

instance createMapBoard Int -> Int -> MapBoard where
  createMapBoard n m = createMapBoard indices squares where
  indices = defineIndices n m
  squares = createBoard n m

이를 컴파일하려고하면 컴파일 오류가 발생합니다.

src/minesweeper.hs:35:19-26: error: …
    Unexpected type ‘MapBoard’
    In the class declaration for ‘MyClass’
    A class declaration should have form
      class MyClass a b c where ...
   |
Compilation failed.
λ> 

클래스 정의에서 MapBoard와 같은 비 대수 유형을 사용할 수없는 이유가 혼란 스럽습니다.

class MyClass a b MapBoard where

MapBoard를 다른 대수 유형 c로 대체하면 또 다른 컴파일 오류가 발생하여 손실됩니다.

src/minesweeper.hs:37:10-63: error: …
    Illegal class instance: ‘createMapBoard [[(Int, Int)]]
                             -> [[Square]] -> MapBoard’
      Class instances must be of the form
        context => C ty_1 ... ty_n
      where ‘C’ is a class
   |
src/minesweeper.hs:39:10-46: error: …
    Illegal class instance: ‘createMapBoard Int -> Int -> MapBoard’
      Class instances must be of the form
        context => C ty_1 ... ty_n
      where ‘C’ is a class
   |
Compilation failed.

createMapBoard의 임시 다형성을 얻을 수 있습니까? 반환 유형이 모든 인스턴스에 대해 MapBoard 여야한다는 엄격한 제약이있는 클래스 정의를 만들 수 있습니까?

편집하다:

구문 오류를 수정 한 후 내 코드는 다음과 같습니다.

class MyClass a b where
  createMapBoard :: a -> b
instance createMapBoard [[(Int,Int)]] [[Square]] where
  createMapBoard indices squares = M.fromList $ zip (concat indices) (concat squares)
instance createMapBoard Int Int where
  createMapBoard n m = createMapBoard indices squares where
  indices = defineIndices n m
  squares = createBoard n m

이로 인해 또 다른 컴파일 오류가 발생합니다.

src/minesweeper.hs:37:10-23: error: …
    Not in scope: type variable ‘createMapBoard’
   |
src/minesweeper.hs:39:10-23: error: …
    Not in scope: type variable ‘createMapBoard’
   |
Compilation failed.

나는 수업에 대한 나의 이해에 여전히 오류가 있다고 믿는 경향이 있습니다.

좌회전

다음과 같이 작성하고 싶습니다.

class MyClass a b where createMapBoard :: a -> b -> MapBoard

instance MyClass [[(Int,Int)]] [[Square]] where
    createMapBoard indices squares = M.fromList $ zip ...

instance MyClass Int Int where
    createMapBoard n m = createMapBoard indices squares where
        ...

... -> ... -> MapBoard이미 createMapBoard이 클래스 / 인스턴스 머리에 속하지 않는, 방법의 서명.

덧붙여서, 나는 여기에서 수업을 갖는 것이 정말로 의미가 있다고 확신하지 않습니다. 두 개의 개별적으로 명명 된 createMapBoard함수 를 갖는 것은 잘못된 것이 아닙니다 . 클래스는 실제로 다형성 함수를 작성할 수있을 때만 갈 수있는 길이지만,이 경우에는 의심 스럽습니다. 한 버전이 필요한 구체적인 상황이나 다른 버전이 필요합니다. 수업이 필요하지 않고 원하는 버전을 하드 쓰기 만하면됩니다.

클래스 메서드가 아닌 별도의 함수를 사용하는 한 가지 이유는 유형 검사기의 작업을 더 쉽게 만들어주기 때문입니다. 의 인수 createMapBoard가 다형성이 되 자마자 잠재적으로 모든 유형을 가질 수 있습니다 (적어도 유형 검사기에 관한 한). 따라서 다른 곳에서 유형이 완전히 결정된 인수로만 호출 할 수 있습니다. 이제 다른 프로그래밍 언어에서 전달하려는 값의 유형은 일반적으로 어쨌든 고정되어 있지만 Haskell에서는 실제로 다형성 값 도 갖는 것이 매우 일반적 입니다. 가장 간단한 예는 숫자 리터럴 입니다. 유형은 Int없지만 Num a => a.

저는 개인적으로 "역 다형성"이 일반적으로 "순방향 다형성"보다 작업하는 것이 더 좋다고 생각 합니다. 함수에 대한 인수 를 다형성으로 만들지 말고 결과를 만듭니다. 이렇게하면 가장 바깥 쪽 유형의 표현식이 환경에 의해 고정되고 자동으로 모든 하위 표현식이 유형 검사기에 의해 유추됩니다. 다른 방법으로, 모든 개별 표현식의 유형을 수정해야하며 컴파일러는 최종 결과 유형을 추론 할 수 있습니다. 어쨌든 서명으로 수정하고 싶기 때문에 거의 유용하지 않습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관