2012-05-15 2 views
2

부모 함수에서 인스턴스화 된 구조가 있고 그 부모 함수의 함수를 호출하여 해당 인스턴스화 된 데이터를 수정하려고합니다. 고안된 예가 있습니다 :동일한 작업을 수행하기위한 대안은 무엇입니까?

import Data.List 

data MyLists = MyLists { 
    myInts :: [Int], 
    myBools :: [Bool] 
} deriving (Show) 

addIntToList :: Int -> MyLists -> MyLists 
addIntToList x main_lists = 
    main_lists { myInts = Data.List.insert x my_ints } 
    -- might make a call to another child function that modifies main_list here, and so on (i.e., this is the vertical problem I see with this structuring) 
     where 
      my_ints = myInts main_lists 

main :: IO() 
main = do 
    let my_main_lists = MyLists [1,2,3] [False, True, False] 
    let my_new_main_lists = addIntToList 4 my_main_lists 
    print my_new_main_lists 
    let my_new_new_main_lists = addBoolToList True my_new_main_lists 
    print my_new_new_main_lists 
    -- and so on (this is the lateral problem I see with this code structuring) 

이 코드를 구조화하거나 이와 유사한 작업을 수행하는 다른 방법은 무엇입니까? 더 간결한 방법이 있습니까?

자식 함수에 대한 긴 함수 호출 체인을 만들면 특히 냄새가 심합니다 (코드 냄새). 그들 모두는 새로운 MyLists을 돌려 주거나 그냥 아무 것도하지 않고 main_list을 돌려 줄 필요가 있습니다. 부모님은 MyList과 다른 반환 값 (예 : -> (Bool, MyList))을 처리해야 할 수도 있습니다.

그래서 MyList 매개 변수와 반환 값을 필요로하는 함수 호출의 트리 구조를 상상할 수 있습니다. 그것은 최적으로 보이지 않습니다.

다음은 내가 말하고자하는 구체적인 예입니다. https://github.com/mokehehe/monao (haskell의 슈퍼 마리오 클론) 코드를 찾아보십시오. state.monad는 전혀 사용되지 않으며, 코드 전체에 걸쳐 있어야하는 상위 레벨 구조가 있음을 알 수 있습니다 (예 : Main.hs의 GameGame).

+0

예상되는 출력은 무엇입니까? 정렬 할 int 목록이 있습니까? – epsilonhalbe

+0

예상대로 출력됩니다 ('MyLists {myInts = [1,2,3,4], myBools = [False, True, False]}'). 나는이 코드를 구조화하는 더 좋은 방법을 찾고있다. – joshj

+0

'addBoolToList True my_main_lists'에서, 그것은'my_new_main_lists'가되어서는 안됩니까? –

답변

3

당신은 그것을 좀 더 간결하게 만들 수 있습니다 달성하기 위해 노력할 것이다 방법입니다

{-# LANGUAGE RecordWildCards #-} 
import Data.List (insert) 

addIntToList :: Int -> MyLists -> MyLists 
addIntToList x [email protected]{..} = ml{ myInts = insert x myInts } 

MyLists{..}을 패턴은 MyLists 레코드의 속성을 범위로 덤프합니다. 따라서 새 myInts을 초기화 할 때 이전 myInts을 쉽게 참조 할 수 있습니다.

반대로 표현식 컨텍스트에서 ..을 사용하면 범위에있는 해당 이름으로 초기화되지 않은 속성이 채워집니다.

addIntToList x MyLists{..} = MyLists{ myInts = insert x myInts, .. } 

하나 더 멋진 것은 당신이 기록 와일드 카드로 할 수있는 :

someAction = do 
    myInts <- getInts :: IO [Int] 
    myBools <- getBools :: IO [Bool] 
    return MyLists{..} 

또한, Data.List.insert 조금 장황 같이 addIntToList 기능은 쓸 수 있습니다. 당신은이 오기 때문에, insert을 말할 수있다 :

import Data.List 

네임 스페이스에 Data.List에서 모든 이름을 가져옵니다. 이 기능이 마음에 들지 않으면 (예 :당신이) insert라는 자신의 모듈에서 함수를 정의 할 수 있기 때문에, 당신이 자격을 가져올 수 있습니다 : 지금까지 프로그램에서 MyLists을 사용하는 등

import qualified Data.List as List 

… List.insert … 

을의 StateT 모나드 변압기는 매우 도움이된다 :

{-# LANGUAGE RecordWildCards #-} 
import Control.Monad.State 

... 

printList :: StateT MyLists IO() 
printList = liftIO . print =<< get 

program :: StateT MyLists IO() 
program = do 
    printList 
    modify $ addIntToList 4 
    printList 
    modify $ addBoolToList True 
    printList 

main :: IO() 
main = evalStateT program $ MyLists [1,2,3] [False, True, False] 
+1

이 확장은 레코드 작업을 훨씬 쉽게 해주지 만 코드를 구성하는 더 좋은 방법이 있습니까? 그리고 Data.List.x를 사용하는 것이 장황하다는 것을 알았지 만 다른 많은 사람들의 소스 코드를 읽고 배우는 데있어 haskellers가 더 장황해야합니다. 즉, 또는 누군가가 더 나은 의미 론적 강조를 제시하거나, 기능의 출처를 가리키는 호버 블 툴팁을 작성해야합니다. – joshj

+0

@ user175492 : * "이 확장으로 인해 레코드 작업이 훨씬 쉬워졌지만 코드를 구성하는 더 좋은 방법이 있습니까?"* "MyLists"를 사용하는 코드 또는 접근 자 자신에 대해 이야기하고 있습니까? –

+0

@ user175492 : * "그리고 Data.List.x를 사용하는 것은 장황하다. 'qualified qualified Data.List'는'qualified'가 없기 때문에'Data.List'의 모든 이름을 네임 스페이스에 덤프 할 것이므로 추천합니다. –

1

나는 프로 아니에요하지만 내가 RecordWildCards 확장 사용하여이

import Data.List (insert) 

data MyLists = MyLists { myInts :: [Int], 
         myBools :: [Bool] 
         } deriving (Show) 

addIntToList :: Int -> MyLists -> MyLists 
addIntToList i (MyLists is bs) = MyLists (insert i is) bs 
-- if you don't care about order just do (i:is), which is faster 
-- usually lists of i are denoted is (or sometimes I use ii) as a kind of plural 

main :: IO() 
main = do 
    let myMainList = MyLists [1,2,3] [False, True, False] 
    -- you would rather use CamelCase in Haskell than _ 
    print $ addIntToList 4 myMainList 
+0

내가 찾고있는 것이 아니라; 구조화 문제에 관심이 있습니다. 내 원래 게시물을 편집하여 명확하게했습니다. – joshj

2

당신은 MonadStateData.Lens 봐야한다 :

{-# LANGUAGE TemplateHaskell #-} 
{-# LANGUAGE FlexibleContexts #-} 

import Control.Monad.State 
import Data.Lens 
import Data.Lens.Template 
import qualified Data.List 

data MyLists = MyLists { _myInts :: [Int] 
         , _myBools :: [Bool] 
         } deriving (Show) 

$(makeLens ''MyLists) 

addIntToList :: MonadState MyLists m => Int -> m [Int] 
addIntToList i = myInts %= Data.List.insert i 

addBoolToList :: MonadState MyLists m => Bool -> m [Bool] 
addBoolToList b = myBools %= Data.List.insert b 

program :: MonadState MyLists m => m() 
program = do 
    addIntToList 1 
    addBoolToList False 
    addIntToList 2 
    addBoolToList True 
    return() 

main = do 
    let ml = execState program MyLists { _myInts = [] 
            , _myBools = [] 
            } 
    print ml 

편집 :

그게 내가 테스트받지 않은 코드로 타이핑 한 것입니다. 내가 실제로 작동하도록 예제를 변경했습니다! data-lens, data-lens-fddata-lens-template 모듈이 설치되어 있어야합니다 (cabal install 사용).

+0

나는 이것을 가지고 놀고 싶지만 컴파일은하지 않는다. 편집에서 문제를 추가했지만 동료 리뷰가 필요합니다. – joshj

관련 문제